mirror of
https://github.com/brl/mutter.git
synced 2024-12-25 20:32:16 +00:00
backend/native: Add and use transactional KMS API
This commit introduces, and makes use of, a transactional API used for setting up KMS state, later to be applied, potentially atomically. From an API point of view, so is always the case, but in the current implementation, it still uses legacy drmMode* API to apply the state non-atomically. The API consists of various buliding blocks: * MetaKmsUpdate - a set of configuration changes, the higher level handle for handing over configuration to the impl backend. It's used to set mode, assign framebuffers to planes, queue page flips and set connector properties. * MetaKmsPlaneAssignment - the assignment of a framebuffer to a plane. Currently used to map a framebuffer to the primary plane of a CRTC. In the legacy KMS implementation, the plane assignment is used to derive the framebuffer used for mode setting and page flipping. This also means various high level changes: State, excluding configuring the cursor plane and creating/destroying DRM framebuffer handles, are applied in the end of a clutter frame, in one go. From an API point of view, this is done atomically, but as mentioned, only the non-atomic implementation exists so far. From MetaRendererNative's point of view, a page flip now initially always succeeds; the handling of EBUSY errors are done asynchronously in the MetaKmsImpl backend (still by retrying at refresh rate, but postponing flip callbacks instead of manipulating the frame clock). Handling of falling back to mode setting instead of page flipping is notified after the fact by a more precise page flip feedback API. EGLStream based page flipping relies on the impl backend not being atomic, as the page flipping is done in the EGLStream backend (e.g. nvidia driver). It uses a 'custom' page flip queueing method, keeping the EGLStream logic inside meta-renderer-native.c. Page flip handling is moved to meta-kms-impl-device.c from meta-gpu-kms.c. It goes via an extra idle callback before reaching meta-renderer-native.c to make sure callbacks are invoked outside of the impl context. While dummy power save page flipping is kept in meta-renderer-native.c, the EBUSY handling is moved to meta-kms-impl-simple.c. Instead of freezing the frame clock, actual page flip callbacks are postponed until all EBUSY retries have either succeeded or failed due to some other error than EBUSY. This effectively inhibits new frames to be drawn, meaning we won't stall waiting on the file descriptor for pending page flips. https://gitlab.gnome.org/GNOME/mutter/issues/548 https://gitlab.gnome.org/GNOME/mutter/merge_requests/525
This commit is contained in:
parent
bea7600471
commit
75dff3e7c9
@ -25,9 +25,12 @@
|
||||
#include "backends/native/meta-crtc-kms.h"
|
||||
|
||||
#include "backends/meta-backend-private.h"
|
||||
#include "backends/meta-logical-monitor.h"
|
||||
#include "backends/native/meta-gpu-kms.h"
|
||||
#include "backends/native/meta-output-kms.h"
|
||||
#include "backends/native/meta-kms-device.h"
|
||||
#include "backends/native/meta-kms-plane.h"
|
||||
#include "backends/native/meta-kms-update.h"
|
||||
|
||||
#define ALL_TRANSFORMS_MASK ((1 << META_MONITOR_N_TRANSFORMS) - 1)
|
||||
|
||||
@ -35,12 +38,11 @@ typedef struct _MetaCrtcKms
|
||||
{
|
||||
MetaKmsCrtc *kms_crtc;
|
||||
|
||||
uint32_t rotation_prop_id;
|
||||
uint32_t rotation_map[META_MONITOR_N_TRANSFORMS];
|
||||
|
||||
MetaKmsPlane *primary_plane;
|
||||
} MetaCrtcKms;
|
||||
|
||||
static GQuark kms_crtc_crtc_kms_quark;
|
||||
|
||||
gboolean
|
||||
meta_crtc_kms_is_transform_handled (MetaCrtc *crtc,
|
||||
MetaMonitorTransform transform)
|
||||
@ -55,60 +57,123 @@ meta_crtc_kms_is_transform_handled (MetaCrtc *crtc,
|
||||
}
|
||||
|
||||
void
|
||||
meta_crtc_kms_apply_transform (MetaCrtc *crtc)
|
||||
meta_crtc_kms_apply_transform (MetaCrtc *crtc,
|
||||
MetaKmsPlaneAssignment *kms_plane_assignment)
|
||||
{
|
||||
MetaCrtcKms *crtc_kms = crtc->driver_private;
|
||||
MetaGpu *gpu = meta_crtc_get_gpu (crtc);
|
||||
MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
|
||||
int kms_fd;
|
||||
MetaMonitorTransform hw_transform;
|
||||
|
||||
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
|
||||
|
||||
hw_transform = crtc->transform;
|
||||
if (!meta_crtc_kms_is_transform_handled (crtc, hw_transform))
|
||||
hw_transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||
if (!meta_crtc_kms_is_transform_handled (crtc, hw_transform))
|
||||
return;
|
||||
|
||||
if (drmModeObjectSetProperty (kms_fd,
|
||||
meta_kms_plane_get_id (crtc_kms->primary_plane),
|
||||
DRM_MODE_OBJECT_PLANE,
|
||||
crtc_kms->rotation_prop_id,
|
||||
crtc_kms->rotation_map[hw_transform]) != 0)
|
||||
g_warning ("Failed to apply DRM plane transform %d: %m", hw_transform);
|
||||
meta_kms_plane_update_set_rotation (crtc_kms->primary_plane,
|
||||
kms_plane_assignment,
|
||||
hw_transform);
|
||||
}
|
||||
|
||||
static int
|
||||
find_property_index (MetaGpu *gpu,
|
||||
drmModeObjectPropertiesPtr props,
|
||||
const char *prop_name,
|
||||
drmModePropertyPtr *out_prop)
|
||||
void
|
||||
meta_crtc_kms_assign_primary_plane (MetaCrtc *crtc,
|
||||
uint32_t fb_id,
|
||||
MetaKmsUpdate *kms_update)
|
||||
{
|
||||
MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
|
||||
int kms_fd;
|
||||
unsigned int i;
|
||||
MetaRectangle logical_monitor_rect;
|
||||
int x, y;
|
||||
MetaFixed16Rectangle src_rect;
|
||||
MetaFixed16Rectangle dst_rect;
|
||||
MetaKmsCrtc *kms_crtc;
|
||||
MetaKmsDevice *kms_device;
|
||||
MetaKmsPlane *primary_kms_plane;
|
||||
MetaKmsPlaneAssignment *plane_assignment;
|
||||
|
||||
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
|
||||
logical_monitor_rect =
|
||||
meta_logical_monitor_get_layout (crtc->logical_monitor);
|
||||
x = crtc->rect.x - logical_monitor_rect.x;
|
||||
y = crtc->rect.y - logical_monitor_rect.y;
|
||||
src_rect = (MetaFixed16Rectangle) {
|
||||
.x = meta_fixed_16_from_int (x),
|
||||
.y = meta_fixed_16_from_int (y),
|
||||
.width = meta_fixed_16_from_int (crtc->rect.width),
|
||||
.height = meta_fixed_16_from_int (crtc->rect.height),
|
||||
};
|
||||
dst_rect = (MetaFixed16Rectangle) {
|
||||
.x = meta_fixed_16_from_int (0),
|
||||
.y = meta_fixed_16_from_int (0),
|
||||
.width = meta_fixed_16_from_int (crtc->rect.width),
|
||||
.height = meta_fixed_16_from_int (crtc->rect.height),
|
||||
};
|
||||
|
||||
for (i = 0; i < props->count_props; i++)
|
||||
kms_crtc = meta_crtc_kms_get_kms_crtc (crtc);
|
||||
kms_device = meta_kms_crtc_get_device (kms_crtc);
|
||||
primary_kms_plane = meta_kms_device_get_primary_plane_for (kms_device,
|
||||
kms_crtc);
|
||||
plane_assignment = meta_kms_update_assign_plane (kms_update,
|
||||
kms_crtc,
|
||||
primary_kms_plane,
|
||||
fb_id,
|
||||
src_rect,
|
||||
dst_rect);
|
||||
meta_crtc_kms_apply_transform (crtc, plane_assignment);
|
||||
}
|
||||
|
||||
static GList *
|
||||
generate_crtc_connector_list (MetaGpu *gpu,
|
||||
MetaCrtc *crtc)
|
||||
{
|
||||
GList *connectors = NULL;
|
||||
GList *l;
|
||||
|
||||
for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
|
||||
{
|
||||
drmModePropertyPtr prop;
|
||||
MetaOutput *output = l->data;
|
||||
MetaCrtc *assigned_crtc;
|
||||
|
||||
prop = drmModeGetProperty (kms_fd, props->props[i]);
|
||||
if (!prop)
|
||||
continue;
|
||||
|
||||
if (strcmp (prop->name, prop_name) == 0)
|
||||
assigned_crtc = meta_output_get_assigned_crtc (output);
|
||||
if (assigned_crtc == crtc)
|
||||
{
|
||||
*out_prop = prop;
|
||||
return i;
|
||||
}
|
||||
MetaKmsConnector *kms_connector =
|
||||
meta_output_kms_get_kms_connector (output);
|
||||
|
||||
drmModeFreeProperty (prop);
|
||||
connectors = g_list_prepend (connectors, kms_connector);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return connectors;
|
||||
}
|
||||
|
||||
void
|
||||
meta_crtc_kms_set_mode (MetaCrtc *crtc,
|
||||
MetaKmsUpdate *kms_update)
|
||||
{
|
||||
MetaGpu *gpu = meta_crtc_get_gpu (crtc);
|
||||
GList *connectors;
|
||||
drmModeModeInfo *mode;
|
||||
|
||||
connectors = generate_crtc_connector_list (gpu, crtc);
|
||||
|
||||
if (connectors)
|
||||
mode = crtc->current_mode->driver_private;
|
||||
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 *
|
||||
@ -176,62 +241,10 @@ meta_crtc_kms_supports_format (MetaCrtc *crtc,
|
||||
drm_format);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_transforms (MetaCrtc *crtc,
|
||||
drmModePropertyPtr prop)
|
||||
MetaCrtc *
|
||||
meta_crtc_kms_from_kms_crtc (MetaKmsCrtc *kms_crtc)
|
||||
{
|
||||
MetaCrtcKms *crtc_kms = crtc->driver_private;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < prop->count_enums; i++)
|
||||
{
|
||||
int transform = -1;
|
||||
|
||||
if (strcmp (prop->enums[i].name, "rotate-0") == 0)
|
||||
transform = META_MONITOR_TRANSFORM_NORMAL;
|
||||
else if (strcmp (prop->enums[i].name, "rotate-90") == 0)
|
||||
transform = META_MONITOR_TRANSFORM_90;
|
||||
else if (strcmp (prop->enums[i].name, "rotate-180") == 0)
|
||||
transform = META_MONITOR_TRANSFORM_180;
|
||||
else if (strcmp (prop->enums[i].name, "rotate-270") == 0)
|
||||
transform = META_MONITOR_TRANSFORM_270;
|
||||
|
||||
if (transform != -1)
|
||||
crtc_kms->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);
|
||||
return g_object_get_qdata (G_OBJECT (kms_crtc), kms_crtc_crtc_kms_quark);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -287,7 +300,13 @@ meta_create_kms_crtc (MetaGpuKms *gpu_kms,
|
||||
crtc->driver_private = crtc_kms;
|
||||
crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify;
|
||||
|
||||
init_crtc_rotations (crtc, gpu);
|
||||
if (!kms_crtc_crtc_kms_quark)
|
||||
{
|
||||
kms_crtc_crtc_kms_quark =
|
||||
g_quark_from_static_string ("meta-kms-crtc-crtc-kms-quark");
|
||||
}
|
||||
|
||||
g_object_set_qdata (G_OBJECT (kms_crtc), kms_crtc_crtc_kms_quark, crtc);
|
||||
|
||||
return crtc;
|
||||
}
|
||||
|
@ -34,7 +34,23 @@
|
||||
gboolean meta_crtc_kms_is_transform_handled (MetaCrtc *crtc,
|
||||
MetaMonitorTransform transform);
|
||||
|
||||
void meta_crtc_kms_apply_transform (MetaCrtc *crtc);
|
||||
void meta_crtc_kms_apply_transform (MetaCrtc *crtc,
|
||||
MetaKmsPlaneAssignment *kms_plane_assignment);
|
||||
|
||||
void meta_crtc_kms_assign_primary_plane (MetaCrtc *crtc,
|
||||
uint32_t fb_id,
|
||||
MetaKmsUpdate *kms_update);
|
||||
|
||||
void meta_crtc_kms_set_mode (MetaCrtc *crtc,
|
||||
MetaKmsUpdate *kms_update);
|
||||
|
||||
void meta_crtc_kms_page_flip (MetaCrtc *crtc,
|
||||
const MetaKmsPageFlipFeedback *page_flip_feedback,
|
||||
gpointer user_data,
|
||||
MetaKmsUpdate *kms_update);
|
||||
|
||||
void meta_crtc_kms_set_is_underscanning (MetaCrtc *crtc,
|
||||
gboolean is_underscanning);
|
||||
|
||||
MetaKmsCrtc * meta_crtc_kms_get_kms_crtc (MetaCrtc *crtc);
|
||||
|
||||
@ -48,6 +64,8 @@ gboolean
|
||||
meta_crtc_kms_supports_format (MetaCrtc *crtc,
|
||||
uint32_t drm_format);
|
||||
|
||||
MetaCrtc * meta_crtc_kms_from_kms_crtc (MetaKmsCrtc *kms_crtc);
|
||||
|
||||
MetaCrtc * meta_create_kms_crtc (MetaGpuKms *gpu_kms,
|
||||
MetaKmsCrtc *kms_crtc);
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "backends/native/meta-crtc-kms.h"
|
||||
#include "backends/native/meta-kms-connector.h"
|
||||
#include "backends/native/meta-kms-device.h"
|
||||
#include "backends/native/meta-kms-update.h"
|
||||
#include "backends/native/meta-kms-utils.h"
|
||||
#include "backends/native/meta-kms.h"
|
||||
#include "backends/native/meta-launcher.h"
|
||||
@ -46,21 +47,6 @@
|
||||
|
||||
#include "meta-default-modes.h"
|
||||
|
||||
typedef struct _MetaKmsSource
|
||||
{
|
||||
GSource source;
|
||||
|
||||
gpointer fd_tag;
|
||||
MetaGpuKms *gpu_kms;
|
||||
} MetaKmsSource;
|
||||
|
||||
typedef struct _MetaGpuKmsFlipClosureContainer
|
||||
{
|
||||
GClosure *flip_closure;
|
||||
MetaGpuKms *gpu_kms;
|
||||
MetaCrtc *crtc;
|
||||
} MetaGpuKmsFlipClosureContainer;
|
||||
|
||||
struct _MetaGpuKms
|
||||
{
|
||||
MetaGpu parent;
|
||||
@ -69,7 +55,6 @@ struct _MetaGpuKms
|
||||
|
||||
uint32_t id;
|
||||
int fd;
|
||||
GSource *source;
|
||||
|
||||
clockid_t clock_id;
|
||||
|
||||
@ -78,124 +63,6 @@ struct _MetaGpuKms
|
||||
|
||||
G_DEFINE_TYPE (MetaGpuKms, meta_gpu_kms, META_TYPE_GPU)
|
||||
|
||||
static gboolean
|
||||
kms_event_check (GSource *source)
|
||||
{
|
||||
MetaKmsSource *kms_source = (MetaKmsSource *) source;
|
||||
|
||||
return g_source_query_unix_fd (source, kms_source->fd_tag) & G_IO_IN;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
kms_event_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaKmsSource *kms_source = (MetaKmsSource *) source;
|
||||
|
||||
meta_gpu_kms_wait_for_flip (kms_source->gpu_kms, NULL);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static GSourceFuncs kms_event_funcs = {
|
||||
NULL,
|
||||
kms_event_check,
|
||||
kms_event_dispatch
|
||||
};
|
||||
|
||||
static void
|
||||
get_crtc_drm_connectors (MetaGpu *gpu,
|
||||
MetaCrtc *crtc,
|
||||
uint32_t **connectors,
|
||||
unsigned int *n_connectors)
|
||||
{
|
||||
GArray *connectors_array = g_array_new (FALSE, FALSE, sizeof (uint32_t));
|
||||
GList *l;
|
||||
|
||||
for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
|
||||
{
|
||||
MetaOutput *output = l->data;
|
||||
MetaCrtc *assigned_crtc;
|
||||
|
||||
assigned_crtc = meta_output_get_assigned_crtc (output);
|
||||
if (assigned_crtc == crtc)
|
||||
{
|
||||
uint32_t connector_id;
|
||||
|
||||
connector_id = meta_output_kms_get_connector_id (output);
|
||||
g_array_append_val (connectors_array, connector_id);
|
||||
}
|
||||
}
|
||||
|
||||
*n_connectors = connectors_array->len;
|
||||
*connectors = (uint32_t *) g_array_free (connectors_array, FALSE);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_gpu_kms_apply_crtc_mode (MetaGpuKms *gpu_kms,
|
||||
MetaCrtc *crtc,
|
||||
int x,
|
||||
int y,
|
||||
uint32_t fb_id)
|
||||
{
|
||||
MetaGpu *gpu = meta_crtc_get_gpu (crtc);
|
||||
int kms_fd = meta_gpu_kms_get_fd (gpu_kms);
|
||||
uint32_t *connectors;
|
||||
unsigned int n_connectors;
|
||||
drmModeModeInfo *mode;
|
||||
|
||||
get_crtc_drm_connectors (gpu, crtc, &connectors, &n_connectors);
|
||||
|
||||
if (connectors)
|
||||
mode = crtc->current_mode->driver_private;
|
||||
else
|
||||
mode = NULL;
|
||||
|
||||
if (drmModeSetCrtc (kms_fd,
|
||||
crtc->crtc_id,
|
||||
fb_id,
|
||||
x, y,
|
||||
connectors, n_connectors,
|
||||
mode) != 0)
|
||||
{
|
||||
if (mode)
|
||||
g_warning ("Failed to set CRTC mode %s: %m", crtc->current_mode->name);
|
||||
else
|
||||
g_warning ("Failed to disable CRTC");
|
||||
g_free (connectors);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_free (connectors);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
invoke_flip_closure (GClosure *flip_closure,
|
||||
MetaGpuKms *gpu_kms,
|
||||
MetaCrtc *crtc,
|
||||
int64_t page_flip_time_ns)
|
||||
{
|
||||
GValue params[] = {
|
||||
G_VALUE_INIT,
|
||||
G_VALUE_INIT,
|
||||
G_VALUE_INIT,
|
||||
G_VALUE_INIT,
|
||||
};
|
||||
|
||||
g_value_init (¶ms[0], G_TYPE_POINTER);
|
||||
g_value_set_pointer (¶ms[0], flip_closure);
|
||||
g_value_init (¶ms[1], G_TYPE_OBJECT);
|
||||
g_value_set_object (¶ms[1], gpu_kms);
|
||||
g_value_init (¶ms[2], G_TYPE_OBJECT);
|
||||
g_value_set_object (¶ms[2], crtc);
|
||||
g_value_init (¶ms[3], G_TYPE_INT64);
|
||||
g_value_set_int64 (¶ms[3], page_flip_time_ns);
|
||||
g_closure_invoke (flip_closure, NULL, 4, params, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
|
||||
MetaCrtc *crtc)
|
||||
@ -232,79 +99,6 @@ meta_gpu_kms_is_crtc_active (MetaGpuKms *gpu_kms,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MetaGpuKmsFlipClosureContainer *
|
||||
meta_gpu_kms_wrap_flip_closure (MetaGpuKms *gpu_kms,
|
||||
MetaCrtc *crtc,
|
||||
GClosure *flip_closure)
|
||||
{
|
||||
MetaGpuKmsFlipClosureContainer *closure_container;
|
||||
|
||||
closure_container = g_new0 (MetaGpuKmsFlipClosureContainer, 1);
|
||||
*closure_container = (MetaGpuKmsFlipClosureContainer) {
|
||||
.flip_closure = g_closure_ref (flip_closure),
|
||||
.gpu_kms = gpu_kms,
|
||||
.crtc = crtc
|
||||
};
|
||||
|
||||
return closure_container;
|
||||
}
|
||||
|
||||
void
|
||||
meta_gpu_kms_flip_closure_container_free (MetaGpuKmsFlipClosureContainer *closure_container)
|
||||
{
|
||||
g_closure_unref (closure_container->flip_closure);
|
||||
g_free (closure_container);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms,
|
||||
MetaCrtc *crtc,
|
||||
uint32_t fb_id,
|
||||
GClosure *flip_closure,
|
||||
GError **error)
|
||||
{
|
||||
MetaGpu *gpu = META_GPU (gpu_kms);
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
static int64_t
|
||||
timeval_to_nanoseconds (const struct timeval *tv)
|
||||
{
|
||||
int64_t usec = ((int64_t) tv->tv_sec) * G_USEC_PER_SEC + tv->tv_usec;
|
||||
int64_t nsec = usec * 1000;
|
||||
|
||||
return nsec;
|
||||
}
|
||||
|
||||
static void
|
||||
page_flip_handler (int fd,
|
||||
unsigned int frame,
|
||||
unsigned int sec,
|
||||
unsigned int usec,
|
||||
void *user_data)
|
||||
{
|
||||
MetaGpuKmsFlipClosureContainer *closure_container = user_data;
|
||||
GClosure *flip_closure = closure_container->flip_closure;
|
||||
MetaGpuKms *gpu_kms = closure_container->gpu_kms;
|
||||
struct timeval page_flip_time = {sec, usec};
|
||||
|
||||
invoke_flip_closure (flip_closure,
|
||||
gpu_kms,
|
||||
closure_container->crtc,
|
||||
timeval_to_nanoseconds (&page_flip_time));
|
||||
meta_gpu_kms_flip_closure_container_free (closure_container);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_gpu_kms_wait_for_flip (MetaGpuKms *gpu_kms,
|
||||
GError **error)
|
||||
{
|
||||
drmEventContext evctx;
|
||||
|
||||
memset (&evctx, 0, sizeof evctx);
|
||||
evctx.version = 2;
|
||||
evctx.page_flip_handler = page_flip_handler;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
if (drmHandleEvent (gpu_kms->fd, &evctx) != 0)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
int ret;
|
||||
|
||||
if (errno != EAGAIN)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pfd.fd = gpu_kms->fd;
|
||||
pfd.events = POLL_IN | POLL_ERR;
|
||||
do
|
||||
{
|
||||
ret = poll (&pfd, 1, -1);
|
||||
}
|
||||
while (ret == -1 && errno == EINTR);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (meta_kms_device_dispatch_sync (gpu_kms->kms_device, error) < 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -418,8 +153,9 @@ meta_gpu_kms_get_current_time_ns (MetaGpuKms *gpu_kms)
|
||||
}
|
||||
|
||||
void
|
||||
meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
|
||||
uint64_t state)
|
||||
meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
|
||||
uint64_t state,
|
||||
MetaKmsUpdate *kms_update)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
@ -427,7 +163,7 @@ meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
|
||||
{
|
||||
MetaOutput *output = l->data;
|
||||
|
||||
meta_output_kms_set_power_save_mode (output, state);
|
||||
meta_output_kms_set_power_save_mode (output, state, kms_update);
|
||||
}
|
||||
}
|
||||
|
||||
@ -707,16 +443,13 @@ init_outputs (MetaGpuKms *gpu_kms)
|
||||
for (l = meta_kms_device_get_connectors (gpu_kms->kms_device); l; l = l->next)
|
||||
{
|
||||
MetaKmsConnector *kms_connector = l->data;
|
||||
const MetaKmsConnectorState *connector_state;
|
||||
MetaOutput *output;
|
||||
MetaOutput *old_output;
|
||||
GError *error = NULL;
|
||||
uint32_t connector_id;
|
||||
drmModeConnector *connector;
|
||||
|
||||
connector_id = meta_kms_connector_get_id (kms_connector);
|
||||
connector = drmModeGetConnector (gpu_kms->fd, connector_id);
|
||||
|
||||
if (!connector || connector->connection != DRM_MODE_CONNECTED)
|
||||
connector_state = meta_kms_connector_get_current_state (kms_connector);
|
||||
if (!connector_state)
|
||||
continue;
|
||||
|
||||
old_output =
|
||||
@ -724,7 +457,6 @@ init_outputs (MetaGpuKms *gpu_kms)
|
||||
meta_kms_connector_get_id (kms_connector));
|
||||
output = meta_create_kms_output (gpu_kms,
|
||||
kms_connector,
|
||||
connector,
|
||||
old_output,
|
||||
&error);
|
||||
if (!output)
|
||||
@ -787,8 +519,6 @@ meta_gpu_kms_new (MetaBackendNative *backend_native,
|
||||
MetaKmsDevice *kms_device,
|
||||
GError **error)
|
||||
{
|
||||
GSource *source;
|
||||
MetaKmsSource *kms_source;
|
||||
MetaGpuKms *gpu_kms;
|
||||
int kms_fd;
|
||||
|
||||
@ -803,29 +533,9 @@ meta_gpu_kms_new (MetaBackendNative *backend_native,
|
||||
|
||||
meta_gpu_kms_read_current (META_GPU (gpu_kms), NULL);
|
||||
|
||||
source = g_source_new (&kms_event_funcs, sizeof (MetaKmsSource));
|
||||
kms_source = (MetaKmsSource *) source;
|
||||
kms_source->fd_tag = g_source_add_unix_fd (source,
|
||||
gpu_kms->fd,
|
||||
G_IO_IN | G_IO_ERR);
|
||||
kms_source->gpu_kms = gpu_kms;
|
||||
|
||||
gpu_kms->source = source;
|
||||
g_source_attach (gpu_kms->source, NULL);
|
||||
|
||||
return gpu_kms;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_gpu_kms_finalize (GObject *object)
|
||||
{
|
||||
MetaGpuKms *gpu_kms = META_GPU_KMS (object);
|
||||
|
||||
g_source_destroy (gpu_kms->source);
|
||||
|
||||
G_OBJECT_CLASS (meta_gpu_kms_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_gpu_kms_init (MetaGpuKms *gpu_kms)
|
||||
{
|
||||
@ -838,10 +548,7 @@ meta_gpu_kms_init (MetaGpuKms *gpu_kms)
|
||||
static void
|
||||
meta_gpu_kms_class_init (MetaGpuKmsClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
MetaGpuClass *gpu_class = META_GPU_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_gpu_kms_finalize;
|
||||
|
||||
gpu_class->read_current = meta_gpu_kms_read_current;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include "backends/meta-gpu.h"
|
||||
#include "backends/native/meta-backend-native.h"
|
||||
#include "backends/native/meta-kms-types.h"
|
||||
|
||||
#define META_TYPE_GPU_KMS (meta_gpu_kms_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaGpuKms, meta_gpu_kms, META, GPU_KMS, MetaGpu)
|
||||
@ -39,12 +40,6 @@ MetaGpuKms * meta_gpu_kms_new (MetaBackendNative *backend_native,
|
||||
MetaKmsDevice *kms_device,
|
||||
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_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_platform_device (MetaGpuKms *gpu_kms);
|
||||
|
||||
gboolean meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms,
|
||||
MetaCrtc *crtc,
|
||||
uint32_t fb_id,
|
||||
GClosure *flip_closure,
|
||||
GError **error);
|
||||
|
||||
gboolean meta_gpu_kms_wait_for_flip (MetaGpuKms *gpu_kms,
|
||||
GError **error);
|
||||
|
||||
@ -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);
|
||||
|
||||
void meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
|
||||
uint64_t state);
|
||||
void meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
|
||||
uint64_t state,
|
||||
MetaKmsUpdate *kms_update);
|
||||
|
||||
MetaCrtcMode * meta_gpu_kms_get_mode_from_drm_mode (MetaGpuKms *gpu_kms,
|
||||
const drmModeModeInfo *drm_mode);
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include "backends/native/meta-kms-device-private.h"
|
||||
#include "backends/native/meta-kms-impl-device.h"
|
||||
#include "backends/native/meta-kms-update-private.h"
|
||||
|
||||
struct _MetaKmsConnector
|
||||
{
|
||||
@ -38,6 +39,13 @@ struct _MetaKmsConnector
|
||||
char *name;
|
||||
|
||||
MetaKmsConnectorState *current_state;
|
||||
|
||||
uint32_t dpms_prop_id;
|
||||
uint32_t underscan_prop_id;
|
||||
uint32_t underscan_hborder_prop_id;
|
||||
uint32_t underscan_vborder_prop_id;
|
||||
uint32_t edid_blob_id;
|
||||
uint32_t tile_blob_id;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaKmsConnector, meta_kms_connector, G_TYPE_OBJECT)
|
||||
@ -48,6 +56,47 @@ meta_kms_connector_get_device (MetaKmsConnector *connector)
|
||||
return connector->device;
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_connector_update_set_dpms_state (MetaKmsConnector *connector,
|
||||
MetaKmsUpdate *update,
|
||||
uint64_t state)
|
||||
{
|
||||
meta_kms_update_set_connector_property (update,
|
||||
connector,
|
||||
connector->dpms_prop_id,
|
||||
state);
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_connector_set_underscanning (MetaKmsConnector *connector,
|
||||
MetaKmsUpdate *update,
|
||||
uint64_t hborder,
|
||||
uint64_t vborder)
|
||||
{
|
||||
meta_kms_update_set_connector_property (update,
|
||||
connector,
|
||||
connector->underscan_prop_id,
|
||||
1);
|
||||
meta_kms_update_set_connector_property (update,
|
||||
connector,
|
||||
connector->underscan_hborder_prop_id,
|
||||
hborder);
|
||||
meta_kms_update_set_connector_property (update,
|
||||
connector,
|
||||
connector->underscan_vborder_prop_id,
|
||||
vborder);
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_connector_unset_underscanning (MetaKmsConnector *connector,
|
||||
MetaKmsUpdate *update)
|
||||
{
|
||||
meta_kms_update_set_connector_property (update,
|
||||
connector,
|
||||
connector->underscan_prop_id,
|
||||
0);
|
||||
}
|
||||
|
||||
MetaConnectorType
|
||||
meta_kms_connector_get_connector_type (MetaKmsConnector *connector)
|
||||
{
|
||||
@ -89,6 +138,12 @@ meta_kms_connector_get_current_state (MetaKmsConnector *connector)
|
||||
return connector->current_state;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_kms_connector_is_underscanning_supported (MetaKmsConnector *connector)
|
||||
{
|
||||
return connector->underscan_prop_id != 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_panel_orientation (MetaKmsConnectorState *state,
|
||||
drmModePropertyPtr prop,
|
||||
@ -437,6 +492,41 @@ meta_kms_connector_update_state (MetaKmsConnector *connector,
|
||||
drm_resources);
|
||||
}
|
||||
|
||||
static void
|
||||
find_property_ids (MetaKmsConnector *connector,
|
||||
MetaKmsImplDevice *impl_device,
|
||||
drmModeConnector *drm_connector)
|
||||
{
|
||||
int fd;
|
||||
int i;
|
||||
|
||||
fd = meta_kms_impl_device_get_fd (impl_device);
|
||||
|
||||
for (i = 0; i < drm_connector->count_props; i++)
|
||||
{
|
||||
drmModePropertyPtr prop;
|
||||
|
||||
prop = drmModeGetProperty (fd, drm_connector->props[i]);
|
||||
if (!prop)
|
||||
continue;
|
||||
|
||||
if ((prop->flags & DRM_MODE_PROP_ENUM) &&
|
||||
strcmp (prop->name, "DPMS") == 0)
|
||||
connector->dpms_prop_id = prop->prop_id;
|
||||
else if ((prop->flags & DRM_MODE_PROP_ENUM) &&
|
||||
strcmp (prop->name, "underscan") == 0)
|
||||
connector->underscan_prop_id = prop->prop_id;
|
||||
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
|
||||
strcmp (prop->name, "underscan hborder") == 0)
|
||||
connector->underscan_hborder_prop_id = prop->prop_id;
|
||||
else if ((prop->flags & DRM_MODE_PROP_RANGE) &&
|
||||
strcmp (prop->name, "underscan vborder") == 0)
|
||||
connector->underscan_vborder_prop_id = prop->prop_id;
|
||||
|
||||
drmModeFreeProperty (prop);
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
make_connector_name (drmModeConnector *drm_connector)
|
||||
{
|
||||
@ -483,6 +573,8 @@ meta_kms_connector_new (MetaKmsImplDevice *impl_device,
|
||||
connector->type = (MetaConnectorType) drm_connector->connector_type;
|
||||
connector->name = make_connector_name (drm_connector);
|
||||
|
||||
find_property_ids (connector, impl_device, drm_connector);
|
||||
|
||||
meta_kms_connector_read_state (connector, impl_device,
|
||||
drm_connector,
|
||||
drm_resources);
|
||||
|
@ -61,6 +61,18 @@ typedef struct _MetaKmsConnectorState
|
||||
|
||||
MetaKmsDevice * meta_kms_connector_get_device (MetaKmsConnector *connector);
|
||||
|
||||
void meta_kms_connector_update_set_dpms_state (MetaKmsConnector *connector,
|
||||
MetaKmsUpdate *update,
|
||||
uint64_t state);
|
||||
|
||||
void meta_kms_connector_set_underscanning (MetaKmsConnector *connector,
|
||||
MetaKmsUpdate *update,
|
||||
uint64_t hborder,
|
||||
uint64_t vborder);
|
||||
|
||||
void meta_kms_connector_unset_underscanning (MetaKmsConnector *connector,
|
||||
MetaKmsUpdate *update);
|
||||
|
||||
MetaConnectorType meta_kms_connector_get_connector_type (MetaKmsConnector *connector);
|
||||
|
||||
uint32_t meta_kms_connector_get_id (MetaKmsConnector *connector);
|
||||
@ -72,4 +84,6 @@ gboolean meta_kms_connector_can_clone (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 */
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "backends/native/meta-kms-device-private.h"
|
||||
#include "backends/native/meta-kms-impl-device.h"
|
||||
#include "backends/native/meta-kms-update-private.h"
|
||||
|
||||
struct _MetaKmsCrtc
|
||||
{
|
||||
|
@ -108,6 +108,35 @@ meta_kms_device_get_primary_plane_for (MetaKmsDevice *device,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dispatch_in_impl (MetaKmsImpl *impl,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (user_data);
|
||||
|
||||
return meta_kms_impl_device_dispatch (impl_device, error);
|
||||
}
|
||||
|
||||
int
|
||||
meta_kms_device_dispatch_sync (MetaKmsDevice *device,
|
||||
GError **error)
|
||||
{
|
||||
int callback_count;
|
||||
|
||||
callback_count = meta_kms_flush_callbacks (device->kms);
|
||||
if (callback_count > 0)
|
||||
return TRUE;
|
||||
|
||||
if (!meta_kms_run_impl_task_sync (device->kms,
|
||||
dispatch_in_impl,
|
||||
device->impl_device,
|
||||
error))
|
||||
return -1;
|
||||
|
||||
return meta_kms_flush_callbacks (device->kms);
|
||||
}
|
||||
|
||||
typedef struct _CreateImplDeviceData
|
||||
{
|
||||
MetaKmsDevice *device;
|
||||
|
@ -42,6 +42,9 @@ GList * meta_kms_device_get_crtcs (MetaKmsDevice *device);
|
||||
MetaKmsPlane * meta_kms_device_get_primary_plane_for (MetaKmsDevice *device,
|
||||
MetaKmsCrtc *crtc);
|
||||
|
||||
int meta_kms_device_dispatch_sync (MetaKmsDevice *device,
|
||||
GError **error);
|
||||
|
||||
MetaKmsDevice * meta_kms_device_new (MetaKms *kms,
|
||||
const char *path,
|
||||
MetaKmsDeviceFlag flags,
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "backends/native/meta-kms-impl-device.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <xf86drm.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.h"
|
||||
#include "backends/native/meta-kms-impl.h"
|
||||
#include "backends/native/meta-kms-page-flip-private.h"
|
||||
#include "backends/native/meta-kms-plane.h"
|
||||
#include "backends/native/meta-kms-private.h"
|
||||
#include "backends/native/meta-kms-update.h"
|
||||
|
||||
struct _MetaKmsImplDevice
|
||||
{
|
||||
@ -39,6 +42,7 @@ struct _MetaKmsImplDevice
|
||||
MetaKmsImpl *impl;
|
||||
|
||||
int fd;
|
||||
GSource *fd_source;
|
||||
|
||||
GList *crtcs;
|
||||
GList *connectors;
|
||||
@ -71,6 +75,77 @@ meta_kms_impl_device_copy_planes (MetaKmsImplDevice *impl_device)
|
||||
return g_list_copy (impl_device->planes);
|
||||
}
|
||||
|
||||
static void
|
||||
page_flip_handler (int fd,
|
||||
unsigned int sequence,
|
||||
unsigned int sec,
|
||||
unsigned int usec,
|
||||
void *user_data)
|
||||
{
|
||||
MetaKmsPageFlipData *page_flip_data = user_data;
|
||||
MetaKmsImpl *impl;
|
||||
|
||||
meta_kms_page_flip_data_set_timings_in_impl (page_flip_data,
|
||||
sequence, sec, usec);
|
||||
|
||||
impl = meta_kms_page_flip_data_get_kms_impl (page_flip_data);
|
||||
meta_kms_impl_handle_page_flip_callback (impl, page_flip_data);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_kms_impl_device_dispatch (MetaKmsImplDevice *impl_device,
|
||||
GError **error)
|
||||
{
|
||||
drmEventContext drm_event_context;
|
||||
|
||||
meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl));
|
||||
|
||||
drm_event_context = (drmEventContext) { 0 };
|
||||
drm_event_context.version = 2;
|
||||
drm_event_context.page_flip_handler = page_flip_handler;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
if (drmHandleEvent (impl_device->fd, &drm_event_context) != 0)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
int ret;
|
||||
|
||||
if (errno != EAGAIN)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR,
|
||||
g_io_error_from_errno (errno),
|
||||
strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pfd.fd = impl_device->fd;
|
||||
pfd.events = POLL_IN | POLL_ERR;
|
||||
do
|
||||
{
|
||||
ret = poll (&pfd, 1, -1);
|
||||
}
|
||||
while (ret == -1 && errno == EINTR);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
kms_event_dispatch_in_impl (MetaKmsImpl *impl,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
MetaKmsImplDevice *impl_device = user_data;
|
||||
|
||||
return meta_kms_impl_device_dispatch (impl_device, error);
|
||||
}
|
||||
|
||||
drmModePropertyPtr
|
||||
meta_kms_impl_device_find_property (MetaKmsImplDevice *impl_device,
|
||||
drmModeObjectProperties *props,
|
||||
@ -236,10 +311,11 @@ meta_kms_impl_device_new (MetaKmsDevice *device,
|
||||
MetaKmsImpl *impl,
|
||||
int fd)
|
||||
{
|
||||
MetaKms *kms = meta_kms_impl_get_kms (impl);
|
||||
MetaKmsImplDevice *impl_device;
|
||||
drmModeRes *drm_resources;
|
||||
|
||||
meta_assert_in_kms_impl (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->device = device;
|
||||
@ -256,6 +332,11 @@ meta_kms_impl_device_new (MetaKmsDevice *device,
|
||||
|
||||
drmModeFreeResources (drm_resources);
|
||||
|
||||
impl_device->fd_source =
|
||||
meta_kms_register_fd_in_impl (kms, fd,
|
||||
kms_event_dispatch_in_impl,
|
||||
impl_device);
|
||||
|
||||
return impl_device;
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
g_clear_pointer (&impl_device->fd_source, g_source_destroy);
|
||||
fd = impl_device->fd;
|
||||
impl_device->fd = -1;
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include "backends/native/meta-kms-device.h"
|
||||
#include "backends/native/meta-kms-types.h"
|
||||
#include "backends/native/meta-kms-update.h"
|
||||
|
||||
#define META_TYPE_KMS_IMPL_DEVICE (meta_kms_impl_device_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaKmsImplDevice, meta_kms_impl_device,
|
||||
@ -40,6 +41,9 @@ GList * meta_kms_impl_device_copy_crtcs (MetaKmsImplDevice *impl_device);
|
||||
|
||||
GList * meta_kms_impl_device_copy_planes (MetaKmsImplDevice *impl_device);
|
||||
|
||||
gboolean meta_kms_impl_device_dispatch (MetaKmsImplDevice *impl_device,
|
||||
GError **error);
|
||||
|
||||
drmModePropertyPtr meta_kms_impl_device_find_property (MetaKmsImplDevice *impl_device,
|
||||
drmModeObjectProperties *props,
|
||||
const char *prop_name,
|
||||
|
@ -21,16 +21,47 @@
|
||||
|
||||
#include "backends/native/meta-kms-impl-simple.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <gbm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
||||
#include "backends/native/meta-kms-connector.h"
|
||||
#include "backends/native/meta-kms-crtc.h"
|
||||
#include "backends/native/meta-kms-device-private.h"
|
||||
#include "backends/native/meta-kms-page-flip-private.h"
|
||||
#include "backends/native/meta-kms-plane.h"
|
||||
#include "backends/native/meta-kms-private.h"
|
||||
#include "backends/native/meta-kms-update-private.h"
|
||||
#include "backends/native/meta-kms-utils.h"
|
||||
|
||||
typedef struct _CachedModeSet
|
||||
{
|
||||
GList *connectors;
|
||||
drmModeModeInfo *drm_mode;
|
||||
} CachedModeSet;
|
||||
|
||||
struct _MetaKmsImplSimple
|
||||
{
|
||||
MetaKmsImpl parent;
|
||||
|
||||
GSource *mode_set_fallback_feedback_source;
|
||||
GList *mode_set_fallback_page_flip_datas;
|
||||
|
||||
GList *pending_page_flip_retries;
|
||||
GSource *retry_page_flips_source;
|
||||
|
||||
GList *postponed_page_flip_datas;
|
||||
GList *postponed_mode_set_fallback_datas;
|
||||
|
||||
GHashTable *cached_mode_sets;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaKmsImplSimple, meta_kms_impl_simple,
|
||||
META_TYPE_KMS_IMPL)
|
||||
|
||||
static void
|
||||
flush_postponed_page_flip_datas (MetaKmsImplSimple *impl_simple);
|
||||
|
||||
MetaKmsImplSimple *
|
||||
meta_kms_impl_simple_new (MetaKms *kms,
|
||||
GError **error)
|
||||
@ -40,12 +71,755 @@ meta_kms_impl_simple_new (MetaKms *kms,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
process_connector_property (MetaKmsImpl *impl,
|
||||
MetaKmsUpdate *update,
|
||||
MetaKmsConnectorProperty *connector_property,
|
||||
GError **error)
|
||||
{
|
||||
MetaKmsConnector *connector = connector_property->connector;
|
||||
MetaKmsDevice *device = meta_kms_connector_get_device (connector);
|
||||
MetaKmsImplDevice *impl_device = meta_kms_device_get_impl_device (device);
|
||||
int fd;
|
||||
int ret;
|
||||
|
||||
fd = meta_kms_impl_device_get_fd (impl_device);
|
||||
|
||||
ret = drmModeObjectSetProperty (fd,
|
||||
meta_kms_connector_get_id (connector),
|
||||
DRM_MODE_OBJECT_CONNECTOR,
|
||||
connector_property->prop_id,
|
||||
connector_property->value);
|
||||
if (ret != 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
|
||||
"Failed to set connector %u property %u: %s",
|
||||
meta_kms_connector_get_id (connector),
|
||||
connector_property->prop_id,
|
||||
g_strerror (-ret));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
process_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
|
||||
meta_kms_impl_simple_init (MetaKmsImplSimple *impl_simple)
|
||||
{
|
||||
impl_simple->cached_mode_sets =
|
||||
g_hash_table_new_full (NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(GDestroyNotify) cached_mode_set_free);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_kms_impl_simple_class_init (MetaKmsImplSimpleClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
MetaKmsImplClass *impl_class = META_KMS_IMPL_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_kms_impl_simple_finalize;
|
||||
|
||||
impl_class->process_update = meta_kms_impl_simple_process_update;
|
||||
impl_class->handle_page_flip_callback = meta_kms_impl_simple_handle_page_flip_callback;
|
||||
impl_class->discard_pending_page_flips = meta_kms_impl_simple_discard_pending_page_flips;
|
||||
}
|
||||
|
@ -43,6 +43,28 @@ meta_kms_impl_get_kms (MetaKmsImpl *impl)
|
||||
return priv->kms;
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_kms_impl_process_update (MetaKmsImpl *impl,
|
||||
MetaKmsUpdate *update,
|
||||
GError **error)
|
||||
{
|
||||
return META_KMS_IMPL_GET_CLASS (impl)->process_update (impl, update, error);
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_impl_handle_page_flip_callback (MetaKmsImpl *impl,
|
||||
MetaKmsPageFlipData *page_flip_data)
|
||||
{
|
||||
META_KMS_IMPL_GET_CLASS (impl)->handle_page_flip_callback (impl,
|
||||
page_flip_data);
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_impl_discard_pending_page_flips (MetaKmsImpl *impl)
|
||||
{
|
||||
META_KMS_IMPL_GET_CLASS (impl)->discard_pending_page_flips (impl);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_kms_impl_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define META_KMS_IMPL_H
|
||||
|
||||
#include "backends/native/meta-kms-impl-device.h"
|
||||
#include "backends/native/meta-kms-page-flip-private.h"
|
||||
#include "backends/native/meta-kms.h"
|
||||
|
||||
#define META_TYPE_KMS_IMPL (meta_kms_impl_get_type ())
|
||||
@ -30,8 +31,24 @@ G_DECLARE_DERIVABLE_TYPE (MetaKmsImpl, meta_kms_impl,
|
||||
struct _MetaKmsImplClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
gboolean (* process_update) (MetaKmsImpl *impl,
|
||||
MetaKmsUpdate *update,
|
||||
GError **error);
|
||||
void (* handle_page_flip_callback) (MetaKmsImpl *impl,
|
||||
MetaKmsPageFlipData *page_flip_data);
|
||||
void (* discard_pending_page_flips) (MetaKmsImpl *impl);
|
||||
};
|
||||
|
||||
MetaKms * meta_kms_impl_get_kms (MetaKmsImpl *impl);
|
||||
|
||||
gboolean meta_kms_impl_process_update (MetaKmsImpl *impl,
|
||||
MetaKmsUpdate *update,
|
||||
GError **error);
|
||||
|
||||
void meta_kms_impl_handle_page_flip_callback (MetaKmsImpl *impl,
|
||||
MetaKmsPageFlipData *page_flip_data);
|
||||
|
||||
void meta_kms_impl_discard_pending_page_flips (MetaKmsImpl *impl);
|
||||
|
||||
#endif /* META_KMS_IMPL_H */
|
||||
|
57
src/backends/native/meta-kms-page-flip-private.h
Normal file
57
src/backends/native/meta-kms-page-flip-private.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_KMS_PAGE_FLIP_H
|
||||
#define META_KMS_PAGE_FLIP_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "backends/native/meta-kms-types.h"
|
||||
|
||||
typedef struct _MetaKmsPageFlipData MetaKmsPageFlipData;
|
||||
|
||||
typedef void (* MetaPageFlipDataFeedbackFunc) (MetaKmsPageFlipData *page_flip_data);
|
||||
|
||||
MetaKmsPageFlipData * meta_kms_page_flip_data_new (MetaKmsImpl *impl,
|
||||
MetaKmsCrtc *crtc,
|
||||
const MetaKmsPageFlipFeedback *feedback,
|
||||
gpointer user_data);
|
||||
|
||||
MetaKmsPageFlipData * meta_kms_page_flip_data_ref (MetaKmsPageFlipData *page_flip_data);
|
||||
|
||||
void meta_kms_page_flip_data_unref (MetaKmsPageFlipData *page_flip_data);
|
||||
|
||||
MetaKmsImpl * meta_kms_page_flip_data_get_kms_impl (MetaKmsPageFlipData *page_flip_data);
|
||||
|
||||
void meta_kms_page_flip_data_set_timings_in_impl (MetaKmsPageFlipData *page_flip_data,
|
||||
unsigned int sequence,
|
||||
unsigned int sec,
|
||||
unsigned int usec);
|
||||
|
||||
void meta_kms_page_flip_data_flipped_in_impl (MetaKmsPageFlipData *page_flip_data);
|
||||
|
||||
void meta_kms_page_flip_data_mode_set_fallback_in_impl (MetaKmsPageFlipData *page_flip_data);
|
||||
|
||||
void meta_kms_page_flip_data_discard_in_impl (MetaKmsPageFlipData *page_flip_data,
|
||||
const GError *error);
|
||||
|
||||
void meta_kms_page_flip_data_take_error (MetaKmsPageFlipData *page_flip_data,
|
||||
GError *error);
|
||||
|
||||
#endif /* META_KMS_PAGE_FLIP_H */
|
196
src/backends/native/meta-kms-page-flip.c
Normal file
196
src/backends/native/meta-kms-page-flip.c
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "backends/native/meta-kms-page-flip-private.h"
|
||||
|
||||
#include "backends/native/meta-kms-impl.h"
|
||||
#include "backends/native/meta-kms-private.h"
|
||||
#include "backends/native/meta-kms-update.h"
|
||||
|
||||
struct _MetaKmsPageFlipData
|
||||
{
|
||||
int ref_count;
|
||||
|
||||
MetaKmsImpl *impl;
|
||||
MetaKmsCrtc *crtc;
|
||||
|
||||
const MetaKmsPageFlipFeedback *feedback;
|
||||
gpointer user_data;
|
||||
|
||||
unsigned int sequence;
|
||||
unsigned int sec;
|
||||
unsigned int usec;
|
||||
|
||||
GError *error;
|
||||
};
|
||||
|
||||
MetaKmsPageFlipData *
|
||||
meta_kms_page_flip_data_new (MetaKmsImpl *impl,
|
||||
MetaKmsCrtc *crtc,
|
||||
const MetaKmsPageFlipFeedback *feedback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaKmsPageFlipData *page_flip_data;
|
||||
|
||||
page_flip_data = g_new0 (MetaKmsPageFlipData , 1);
|
||||
*page_flip_data = (MetaKmsPageFlipData) {
|
||||
.ref_count = 1,
|
||||
.impl = impl,
|
||||
.crtc = crtc,
|
||||
.feedback = feedback,
|
||||
.user_data = user_data,
|
||||
};
|
||||
|
||||
return page_flip_data;
|
||||
}
|
||||
|
||||
MetaKmsPageFlipData *
|
||||
meta_kms_page_flip_data_ref (MetaKmsPageFlipData *page_flip_data)
|
||||
{
|
||||
page_flip_data->ref_count++;
|
||||
|
||||
return page_flip_data;
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_page_flip_data_unref (MetaKmsPageFlipData *page_flip_data)
|
||||
{
|
||||
page_flip_data->ref_count--;
|
||||
|
||||
if (page_flip_data->ref_count == 0)
|
||||
{
|
||||
g_clear_error (&page_flip_data->error);
|
||||
g_free (page_flip_data);
|
||||
}
|
||||
}
|
||||
|
||||
MetaKmsImpl *
|
||||
meta_kms_page_flip_data_get_kms_impl (MetaKmsPageFlipData *page_flip_data)
|
||||
{
|
||||
return page_flip_data->impl;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_kms_page_flip_data_flipped (MetaKms *kms,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaKmsPageFlipData *page_flip_data = user_data;
|
||||
|
||||
meta_assert_not_in_kms_impl (kms);
|
||||
|
||||
page_flip_data->feedback->flipped (page_flip_data->crtc,
|
||||
page_flip_data->sequence,
|
||||
page_flip_data->sec,
|
||||
page_flip_data->usec,
|
||||
page_flip_data->user_data);
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_page_flip_data_set_timings_in_impl (MetaKmsPageFlipData *page_flip_data,
|
||||
unsigned int sequence,
|
||||
unsigned int sec,
|
||||
unsigned int usec)
|
||||
{
|
||||
MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl);
|
||||
|
||||
meta_assert_in_kms_impl (kms);
|
||||
|
||||
page_flip_data->sequence = sequence;
|
||||
page_flip_data->sec = sec;
|
||||
page_flip_data->usec = usec;
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_page_flip_data_flipped_in_impl (MetaKmsPageFlipData *page_flip_data)
|
||||
{
|
||||
MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl);
|
||||
|
||||
meta_assert_in_kms_impl (kms);
|
||||
|
||||
meta_kms_queue_callback (kms,
|
||||
meta_kms_page_flip_data_flipped,
|
||||
meta_kms_page_flip_data_ref (page_flip_data),
|
||||
(GDestroyNotify) meta_kms_page_flip_data_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_kms_page_flip_data_mode_set_fallback (MetaKms *kms,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaKmsPageFlipData *page_flip_data = user_data;
|
||||
|
||||
meta_assert_not_in_kms_impl (kms);
|
||||
|
||||
page_flip_data->feedback->mode_set_fallback (page_flip_data->crtc,
|
||||
page_flip_data->user_data);
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_page_flip_data_mode_set_fallback_in_impl (MetaKmsPageFlipData *page_flip_data)
|
||||
{
|
||||
MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl);
|
||||
|
||||
meta_assert_in_kms_impl (kms);
|
||||
|
||||
meta_kms_queue_callback (kms,
|
||||
meta_kms_page_flip_data_mode_set_fallback,
|
||||
meta_kms_page_flip_data_ref (page_flip_data),
|
||||
(GDestroyNotify) meta_kms_page_flip_data_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_kms_page_flip_data_discard (MetaKms *kms,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaKmsPageFlipData *page_flip_data = user_data;
|
||||
|
||||
meta_assert_not_in_kms_impl (kms);
|
||||
|
||||
page_flip_data->feedback->discarded (page_flip_data->crtc,
|
||||
page_flip_data->user_data,
|
||||
page_flip_data->error);
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_page_flip_data_take_error (MetaKmsPageFlipData *page_flip_data,
|
||||
GError *error)
|
||||
{
|
||||
g_assert (!page_flip_data->error);
|
||||
|
||||
page_flip_data->error = error;
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_page_flip_data_discard_in_impl (MetaKmsPageFlipData *page_flip_data,
|
||||
const GError *error)
|
||||
{
|
||||
MetaKms *kms = meta_kms_impl_get_kms (page_flip_data->impl);
|
||||
|
||||
meta_assert_in_kms_impl (kms);
|
||||
|
||||
if (error)
|
||||
meta_kms_page_flip_data_take_error (page_flip_data, g_error_copy (error));
|
||||
|
||||
meta_kms_queue_callback (kms,
|
||||
meta_kms_page_flip_data_discard,
|
||||
meta_kms_page_flip_data_ref (page_flip_data),
|
||||
(GDestroyNotify) meta_kms_page_flip_data_unref);
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
#include "backends/meta-monitor-transform.h"
|
||||
#include "backends/native/meta-kms-crtc.h"
|
||||
#include "backends/native/meta-kms-impl-device.h"
|
||||
#include "backends/native/meta-kms-update-private.h"
|
||||
|
||||
struct _MetaKmsPlane
|
||||
{
|
||||
@ -53,6 +54,12 @@ struct _MetaKmsPlane
|
||||
|
||||
G_DEFINE_TYPE (MetaKmsPlane, meta_kms_plane, G_TYPE_OBJECT)
|
||||
|
||||
MetaKmsDevice *
|
||||
meta_kms_plane_get_device (MetaKmsPlane *plane)
|
||||
{
|
||||
return plane->device;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
meta_kms_plane_get_id (MetaKmsPlane *plane)
|
||||
{
|
||||
@ -65,6 +72,18 @@ meta_kms_plane_get_plane_type (MetaKmsPlane *plane)
|
||||
return plane->type;
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_plane_update_set_rotation (MetaKmsPlane *plane,
|
||||
MetaKmsPlaneAssignment *plane_assignment,
|
||||
MetaMonitorTransform transform)
|
||||
{
|
||||
g_return_if_fail (meta_kms_plane_is_transform_handled (plane, transform));
|
||||
|
||||
meta_kms_plane_assignment_set_plane_property (plane_assignment,
|
||||
plane->rotation_prop_id,
|
||||
plane->rotation_map[transform]);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_kms_plane_is_transform_handled (MetaKmsPlane *plane,
|
||||
MetaMonitorTransform transform)
|
||||
|
@ -43,6 +43,8 @@ MetaKmsPlane * meta_kms_plane_new (MetaKmsPlaneType type,
|
||||
drmModePlane *drm_plane,
|
||||
drmModeObjectProperties *drm_plane_props);
|
||||
|
||||
MetaKmsDevice * meta_kms_plane_get_device (MetaKmsPlane *plane);
|
||||
|
||||
uint32_t meta_kms_plane_get_id (MetaKmsPlane *plane);
|
||||
|
||||
MetaKmsPlaneType meta_kms_plane_get_plane_type (MetaKmsPlane *plane);
|
||||
@ -61,4 +63,8 @@ gboolean meta_kms_plane_is_format_supported (MetaKmsPlane *plane,
|
||||
gboolean meta_kms_plane_is_usable_with (MetaKmsPlane *plane,
|
||||
MetaKmsCrtc *crtc);
|
||||
|
||||
void meta_kms_plane_update_set_rotation (MetaKmsPlane *plane,
|
||||
MetaKmsPlaneAssignment *plane_assignment,
|
||||
MetaMonitorTransform transform);
|
||||
|
||||
#endif /* META_KMS_PLANE_H */
|
||||
|
@ -36,14 +36,17 @@ void meta_kms_queue_callback (MetaKms *kms,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy);
|
||||
|
||||
int meta_kms_flush_callbacks (MetaKms *kms);
|
||||
|
||||
gboolean meta_kms_run_impl_task_sync (MetaKms *kms,
|
||||
MetaKmsImplTaskFunc func,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
|
||||
GSource * meta_kms_add_source_in_impl (MetaKms *kms,
|
||||
GSourceFunc func,
|
||||
gpointer user_data);
|
||||
GSource * meta_kms_add_source_in_impl (MetaKms *kms,
|
||||
GSourceFunc func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy);
|
||||
|
||||
GSource * meta_kms_register_fd_in_impl (MetaKms *kms,
|
||||
int fd,
|
||||
|
@ -20,6 +20,8 @@
|
||||
#ifndef META_KMS_IMPL_TYPES_H
|
||||
#define META_KMS_IMPL_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct _MetaKms MetaKms;
|
||||
typedef struct _MetaKmsDevice MetaKmsDevice;
|
||||
|
||||
@ -27,9 +29,26 @@ typedef struct _MetaKmsPlane MetaKmsPlane;
|
||||
typedef struct _MetaKmsCrtc MetaKmsCrtc;
|
||||
typedef struct _MetaKmsConnector MetaKmsConnector;
|
||||
|
||||
typedef struct _MetaKmsUpdate MetaKmsUpdate;
|
||||
typedef struct _MetaKmsPlaneAssignment MetaKmsPlaneAssignment;
|
||||
typedef struct _MetaKmsModeSet MetaKmsModeSet;
|
||||
|
||||
typedef struct _MetaKmsPageFlipFeedback MetaKmsPageFlipFeedback;
|
||||
|
||||
typedef struct _MetaKmsImpl MetaKmsImpl;
|
||||
typedef struct _MetaKmsImplDevice MetaKmsImplDevice;
|
||||
|
||||
/* 16:16 fixed point */
|
||||
typedef int32_t MetaFixed16;
|
||||
|
||||
typedef struct _MetaFixed16Rectangle
|
||||
{
|
||||
MetaFixed16 x;
|
||||
MetaFixed16 y;
|
||||
MetaFixed16 width;
|
||||
MetaFixed16 height;
|
||||
} MetaFixed16Rectangle;
|
||||
|
||||
typedef enum _MetaKmsDeviceFlag
|
||||
{
|
||||
META_KMS_DEVICE_FLAG_NONE = 0,
|
||||
|
89
src/backends/native/meta-kms-update-private.h
Normal file
89
src/backends/native/meta-kms-update-private.h
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_KMS_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 */
|
236
src/backends/native/meta-kms-update.c
Normal file
236
src/backends/native/meta-kms-update.c
Normal 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);
|
||||
}
|
92
src/backends/native/meta-kms-update.h
Normal file
92
src/backends/native/meta-kms-update.h
Normal 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 */
|
@ -25,6 +25,7 @@
|
||||
#include "backends/native/meta-kms-device-private.h"
|
||||
#include "backends/native/meta-kms-impl.h"
|
||||
#include "backends/native/meta-kms-impl-simple.h"
|
||||
#include "backends/native/meta-kms-update-private.h"
|
||||
#include "backends/native/meta-udev.h"
|
||||
|
||||
typedef struct _MetaKmsCallbackData
|
||||
@ -64,12 +65,86 @@ struct _MetaKms
|
||||
|
||||
GList *devices;
|
||||
|
||||
MetaKmsUpdate *pending_update;
|
||||
|
||||
GList *pending_callbacks;
|
||||
guint callback_source_id;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaKms, meta_kms, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
meta_kms_update_states_in_impl (MetaKms *kms);
|
||||
|
||||
MetaKmsUpdate *
|
||||
meta_kms_ensure_pending_update (MetaKms *kms)
|
||||
{
|
||||
if (!kms->pending_update)
|
||||
kms->pending_update = meta_kms_update_new ();
|
||||
|
||||
return meta_kms_get_pending_update (kms);
|
||||
}
|
||||
|
||||
MetaKmsUpdate *
|
||||
meta_kms_get_pending_update (MetaKms *kms)
|
||||
{
|
||||
return kms->pending_update;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_kms_update_process_in_impl (MetaKmsImpl *impl,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr (MetaKmsUpdate) update = user_data;
|
||||
gboolean ret;
|
||||
|
||||
ret = meta_kms_impl_process_update (impl, update, error);
|
||||
|
||||
if (meta_kms_update_has_mode_set (update))
|
||||
meta_kms_update_states_in_impl (meta_kms_impl_get_kms (impl));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_kms_post_update_sync (MetaKms *kms,
|
||||
MetaKmsUpdate *update,
|
||||
GError **error)
|
||||
{
|
||||
return meta_kms_run_impl_task_sync (kms,
|
||||
meta_kms_update_process_in_impl,
|
||||
update,
|
||||
error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_kms_post_pending_update_sync (MetaKms *kms,
|
||||
GError **error)
|
||||
{
|
||||
return meta_kms_post_update_sync (kms,
|
||||
g_steal_pointer (&kms->pending_update),
|
||||
error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_kms_discard_pending_page_flips_in_impl (MetaKmsImpl *impl,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
meta_kms_impl_discard_pending_page_flips (impl);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_kms_discard_pending_page_flips (MetaKms *kms)
|
||||
{
|
||||
meta_kms_run_impl_task_sync (kms,
|
||||
meta_kms_discard_pending_page_flips_in_impl,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_kms_callback_data_free (MetaKmsCallbackData *callback_data)
|
||||
{
|
||||
@ -78,11 +153,11 @@ meta_kms_callback_data_free (MetaKmsCallbackData *callback_data)
|
||||
g_slice_free (MetaKmsCallbackData, callback_data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
callback_idle (gpointer user_data)
|
||||
static int
|
||||
flush_callbacks (MetaKms *kms)
|
||||
{
|
||||
MetaKms *kms = user_data;
|
||||
GList *l;
|
||||
int callback_count = 0;
|
||||
|
||||
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);
|
||||
meta_kms_callback_data_free (callback_data);
|
||||
callback_count++;
|
||||
}
|
||||
|
||||
g_list_free (kms->pending_callbacks);
|
||||
kms->pending_callbacks = NULL;
|
||||
|
||||
return callback_count;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
callback_idle (gpointer user_data)
|
||||
{
|
||||
MetaKms *kms = user_data;
|
||||
|
||||
flush_callbacks (kms);
|
||||
|
||||
kms->callback_source_id = 0;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
@ -119,6 +205,17 @@ meta_kms_queue_callback (MetaKms *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
|
||||
meta_kms_run_impl_task_sync (MetaKms *kms,
|
||||
MetaKmsImplTaskFunc func,
|
||||
@ -156,9 +253,10 @@ static GSourceFuncs simple_impl_source_funcs = {
|
||||
};
|
||||
|
||||
GSource *
|
||||
meta_kms_add_source_in_impl (MetaKms *kms,
|
||||
GSourceFunc func,
|
||||
gpointer user_data)
|
||||
meta_kms_add_source_in_impl (MetaKms *kms,
|
||||
GSourceFunc func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy)
|
||||
{
|
||||
GSource *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->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 ());
|
||||
|
||||
return source;
|
||||
@ -245,14 +343,13 @@ meta_kms_in_impl_task (MetaKms *kms)
|
||||
return kms->in_impl_task;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_states_in_impl (MetaKmsImpl *impl,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
static void
|
||||
meta_kms_update_states_in_impl (MetaKms *kms)
|
||||
{
|
||||
MetaKms *kms = user_data;
|
||||
GList *l;
|
||||
|
||||
meta_assert_in_kms_impl (kms);
|
||||
|
||||
for (l = kms->devices; l; l = l->next)
|
||||
{
|
||||
MetaKmsDevice *device = l->data;
|
||||
@ -260,6 +357,16 @@ update_states_in_impl (MetaKmsImpl *impl,
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -28,6 +28,15 @@
|
||||
#define META_TYPE_KMS (meta_kms_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaKms, meta_kms, META, KMS, GObject)
|
||||
|
||||
MetaKmsUpdate * meta_kms_ensure_pending_update (MetaKms *kms);
|
||||
|
||||
MetaKmsUpdate * meta_kms_get_pending_update (MetaKms *kms);
|
||||
|
||||
gboolean meta_kms_post_pending_update_sync (MetaKms *kms,
|
||||
GError **error);
|
||||
|
||||
void meta_kms_discard_pending_page_flips (MetaKms *kms);
|
||||
|
||||
MetaBackend * meta_kms_get_backend (MetaKms *kms);
|
||||
|
||||
MetaKmsDevice * meta_kms_create_device (MetaKms *kms,
|
||||
|
@ -54,6 +54,8 @@
|
||||
#include "backends/native/meta-backend-native.h"
|
||||
#include "backends/native/meta-crtc-kms.h"
|
||||
#include "backends/native/meta-gpu-kms.h"
|
||||
#include "backends/native/meta-kms-update.h"
|
||||
#include "backends/native/meta-kms.h"
|
||||
#include "backends/native/meta-launcher.h"
|
||||
#include "backends/native/meta-output-kms.h"
|
||||
#include "backends/native/meta-renderer-native.h"
|
||||
@ -115,6 +117,11 @@ static void
|
||||
meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
|
||||
MetaPowerSave mode)
|
||||
{
|
||||
MetaBackend *backend = meta_monitor_manager_get_backend (manager);
|
||||
MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
|
||||
MetaKms *kms = meta_backend_native_get_kms (backend_native);
|
||||
MetaKmsUpdate *kms_update;
|
||||
g_autoptr (GError) error = NULL;
|
||||
uint64_t state;
|
||||
GList *l;
|
||||
|
||||
@ -135,12 +142,16 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager,
|
||||
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;
|
||||
|
||||
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
|
||||
@ -214,8 +225,6 @@ apply_crtc_assignments (MetaMonitorManager *manager,
|
||||
meta_output_assign_crtc (output, crtc);
|
||||
}
|
||||
}
|
||||
|
||||
meta_crtc_kms_apply_transform (crtc);
|
||||
}
|
||||
/* Disable CRTCs not mentioned in the list (they have is_dirty == FALSE,
|
||||
because they weren't seen in the first loop) */
|
||||
@ -253,8 +262,6 @@ apply_crtc_assignments (MetaMonitorManager *manager,
|
||||
output->is_primary = output_info->is_primary;
|
||||
output->is_presentation = output_info->is_presentation;
|
||||
output->is_underscanning = output_info->is_underscanning;
|
||||
|
||||
meta_output_kms_set_underscan (output);
|
||||
}
|
||||
|
||||
/* Disable outputs not mentioned in the list */
|
||||
|
@ -42,67 +42,42 @@ typedef struct _MetaOutputKms
|
||||
MetaOutput parent;
|
||||
|
||||
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;
|
||||
|
||||
void
|
||||
meta_output_kms_set_underscan (MetaOutput *output)
|
||||
MetaKmsConnector *
|
||||
meta_output_kms_get_kms_connector (MetaOutput *output)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
MetaGpu *gpu = meta_output_get_gpu (output);
|
||||
MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
|
||||
MetaCrtc *crtc;
|
||||
int kms_fd;
|
||||
uint32_t connector_id;
|
||||
|
||||
if (!output_kms->underscan_prop_id)
|
||||
return output_kms->kms_connector;
|
||||
}
|
||||
|
||||
void
|
||||
meta_output_kms_set_underscan (MetaOutput *output,
|
||||
MetaKmsUpdate *kms_update)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
|
||||
if (!output->supports_underscanning)
|
||||
return;
|
||||
|
||||
crtc = meta_output_get_assigned_crtc (output);
|
||||
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
|
||||
connector_id = output_kms->connector->connector_id;
|
||||
|
||||
if (output->is_underscanning && crtc && crtc->current_mode)
|
||||
if (output->is_underscanning)
|
||||
{
|
||||
drmModeObjectSetProperty (kms_fd, connector_id,
|
||||
DRM_MODE_OBJECT_CONNECTOR,
|
||||
output_kms->underscan_prop_id,
|
||||
(uint64_t) 1);
|
||||
MetaCrtc *crtc;
|
||||
uint64_t hborder, vborder;
|
||||
|
||||
if (output_kms->underscan_hborder_prop_id)
|
||||
{
|
||||
uint64_t value;
|
||||
|
||||
value = MIN (128, crtc->current_mode->width * 0.05);
|
||||
drmModeObjectSetProperty (kms_fd, connector_id,
|
||||
DRM_MODE_OBJECT_CONNECTOR,
|
||||
output_kms->underscan_hborder_prop_id,
|
||||
value);
|
||||
}
|
||||
if (output_kms->underscan_vborder_prop_id)
|
||||
{
|
||||
uint64_t value;
|
||||
|
||||
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);
|
||||
}
|
||||
crtc = meta_output_get_assigned_crtc (output);
|
||||
hborder = MIN (128, (uint64_t) round (crtc->current_mode->width * 0.05));
|
||||
vborder = MIN (128, (uint64_t) round (crtc->current_mode->height * 0.05));
|
||||
meta_kms_connector_set_underscanning (output_kms->kms_connector,
|
||||
kms_update,
|
||||
hborder,
|
||||
vborder);
|
||||
}
|
||||
else
|
||||
{
|
||||
drmModeObjectSetProperty (kms_fd, connector_id,
|
||||
DRM_MODE_OBJECT_CONNECTOR,
|
||||
output_kms->underscan_prop_id,
|
||||
(uint64_t) 0);
|
||||
meta_kms_connector_unset_underscanning (output_kms->kms_connector,
|
||||
kms_update);
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,24 +90,15 @@ meta_output_kms_get_connector_id (MetaOutput *output)
|
||||
}
|
||||
|
||||
void
|
||||
meta_output_kms_set_power_save_mode (MetaOutput *output,
|
||||
uint64_t state)
|
||||
meta_output_kms_set_power_save_mode (MetaOutput *output,
|
||||
uint64_t dpms_state,
|
||||
MetaKmsUpdate *kms_update)
|
||||
{
|
||||
MetaOutputKms *output_kms = output->driver_private;
|
||||
MetaGpu *gpu = meta_output_get_gpu (output);
|
||||
MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
|
||||
|
||||
if (output_kms->dpms_prop_id != 0)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = meta_gpu_kms_get_fd (gpu_kms);
|
||||
if (drmModeObjectSetProperty (fd, output_kms->connector->connector_id,
|
||||
DRM_MODE_OBJECT_CONNECTOR,
|
||||
output_kms->dpms_prop_id, state) < 0)
|
||||
g_warning ("Failed to set power save mode for output %s: %s",
|
||||
output->name, strerror (errno));
|
||||
}
|
||||
meta_kms_connector_update_set_dpms_state (output_kms->kms_connector,
|
||||
kms_update,
|
||||
dpms_state);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -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));
|
||||
}
|
||||
|
||||
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
|
||||
meta_output_destroy_notify (MetaOutput *output)
|
||||
{
|
||||
@ -344,7 +276,6 @@ init_output_modes (MetaOutput *output,
|
||||
MetaOutput *
|
||||
meta_create_kms_output (MetaGpuKms *gpu_kms,
|
||||
MetaKmsConnector *kms_connector,
|
||||
drmModeConnector *connector,
|
||||
MetaOutput *old_output,
|
||||
GError **error)
|
||||
{
|
||||
@ -373,8 +304,6 @@ meta_create_kms_output (MetaGpuKms *gpu_kms,
|
||||
|
||||
output_kms->kms_connector = kms_connector;
|
||||
|
||||
find_connector_properties (gpu_kms, output, connector);
|
||||
|
||||
connector_state = meta_kms_connector_get_current_state (kms_connector);
|
||||
|
||||
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_y = connector_state->suggested_y;
|
||||
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);
|
||||
|
||||
|
@ -27,21 +27,24 @@
|
||||
#include "backends/native/meta-gpu-kms.h"
|
||||
#include "backends/native/meta-kms-types.h"
|
||||
|
||||
void meta_output_kms_set_underscan (MetaOutput *output);
|
||||
void meta_output_kms_set_power_save_mode (MetaOutput *output,
|
||||
uint64_t dpms_state,
|
||||
MetaKmsUpdate *kms_update);
|
||||
|
||||
void meta_output_kms_set_power_save_mode (MetaOutput *output,
|
||||
uint64_t state);
|
||||
void meta_output_kms_set_underscan (MetaOutput *output,
|
||||
MetaKmsUpdate *kms_update);
|
||||
|
||||
gboolean meta_output_kms_can_clone (MetaOutput *output,
|
||||
MetaOutput *other_output);
|
||||
|
||||
MetaKmsConnector * meta_output_kms_get_kms_connector (MetaOutput *output);
|
||||
|
||||
uint32_t meta_output_kms_get_connector_id (MetaOutput *output);
|
||||
|
||||
GBytes * meta_output_kms_read_edid (MetaOutput *output);
|
||||
|
||||
MetaOutput * meta_create_kms_output (MetaGpuKms *gpu_kms,
|
||||
MetaKmsConnector *kms_connector,
|
||||
drmModeConnector *connector,
|
||||
MetaOutput *old_output,
|
||||
GError **error);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -610,10 +610,15 @@ if have_native_backend
|
||||
'backends/native/meta-kms-impl-simple.h',
|
||||
'backends/native/meta-kms-impl.c',
|
||||
'backends/native/meta-kms-impl.h',
|
||||
'backends/native/meta-kms-page-flip.c',
|
||||
'backends/native/meta-kms-page-flip-private.h',
|
||||
'backends/native/meta-kms-plane.c',
|
||||
'backends/native/meta-kms-plane.h',
|
||||
'backends/native/meta-kms-private.h',
|
||||
'backends/native/meta-kms-types.h',
|
||||
'backends/native/meta-kms-update-private.h',
|
||||
'backends/native/meta-kms-update.c',
|
||||
'backends/native/meta-kms-update.h',
|
||||
'backends/native/meta-kms-utils.c',
|
||||
'backends/native/meta-kms-utils.h',
|
||||
'backends/native/meta-kms.c',
|
||||
@ -801,14 +806,6 @@ endif
|
||||
|
||||
subdir('meta')
|
||||
|
||||
mutter_marshal = gnome.genmarshal('meta-marshal',
|
||||
sources: ['meta-marshal.list'],
|
||||
prefix: 'meta_marshal',
|
||||
extra_args: ['--quiet'],
|
||||
internal: true,
|
||||
)
|
||||
mutter_built_sources += mutter_marshal
|
||||
|
||||
mutter_built_sources += mutter_enum_types
|
||||
mutter_built_sources += mutter_version
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
VOID:OBJECT,OBJECT,INT64
|
Loading…
Reference in New Issue
Block a user