diff --git a/src/backends/meta-monitor-transform.h b/src/backends/meta-monitor-transform.h index b2cf9ea53..d1c4c41a6 100644 --- a/src/backends/meta-monitor-transform.h +++ b/src/backends/meta-monitor-transform.h @@ -34,6 +34,7 @@ enum _MetaMonitorTransform META_MONITOR_TRANSFORM_FLIPPED_180, META_MONITOR_TRANSFORM_FLIPPED_270, }; +#define META_MONITOR_N_TRANSFORMS (META_MONITOR_TRANSFORM_FLIPPED_270 + 1) /* Returns true if transform causes width and height to be inverted This is true for the odd transforms in the enum */ diff --git a/src/backends/native/meta-gpu-kms.c b/src/backends/native/meta-gpu-kms.c index 12e820abe..235867e99 100644 --- a/src/backends/native/meta-gpu-kms.c +++ b/src/backends/native/meta-gpu-kms.c @@ -895,8 +895,6 @@ meta_gpu_kms_new (MetaBackendNative *backend_native, gpu_kms->kms_device = kms_device; gpu_kms->fd = kms_fd; - drmSetClientCap (gpu_kms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); - meta_gpu_kms_read_current (META_GPU (gpu_kms), NULL); source = g_source_new (&kms_event_funcs, sizeof (MetaKmsSource)); diff --git a/src/backends/native/meta-kms-device.c b/src/backends/native/meta-kms-device.c index eb45eda96..e3fc396fd 100644 --- a/src/backends/native/meta-kms-device.c +++ b/src/backends/native/meta-kms-device.c @@ -38,6 +38,7 @@ struct _MetaKmsDevice char *path; GList *crtcs; + GList *planes; }; G_DEFINE_TYPE (MetaKmsDevice, meta_kms_device, G_TYPE_OBJECT); @@ -73,6 +74,7 @@ typedef struct _CreateImplDeviceData MetaKmsImplDevice *out_impl_device; GList *out_crtcs; + GList *out_planes; } CreateImplDeviceData; static gboolean @@ -87,6 +89,7 @@ create_impl_device_in_impl (MetaKmsImpl *impl, data->out_impl_device = impl_device; data->out_crtcs = meta_kms_impl_device_copy_crtcs (impl_device); + data->out_planes = meta_kms_impl_device_copy_planes (impl_device); return TRUE; } @@ -127,6 +130,7 @@ meta_kms_device_new (MetaKms *kms, device->flags = flags; device->path = g_strdup (path); device->crtcs = data.out_crtcs; + device->planes = data.out_planes; return device; } @@ -166,6 +170,7 @@ meta_kms_device_finalize (GObject *object) GError *error = NULL; g_list_free (device->crtcs); + g_list_free (device->planes); data = (FreeImplDeviceData) { .impl_device = device->impl_device, diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index 231f4a9c6..91c6b7119 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -26,6 +26,7 @@ #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-plane.h" #include "backends/native/meta-kms-private.h" struct _MetaKmsImplDevice @@ -38,6 +39,7 @@ struct _MetaKmsImplDevice int fd; GList *crtcs; + GList *planes; }; G_DEFINE_TYPE (MetaKmsImplDevice, meta_kms_impl_device, G_TYPE_OBJECT) @@ -54,6 +56,42 @@ meta_kms_impl_device_copy_crtcs (MetaKmsImplDevice *impl_device) return g_list_copy (impl_device->crtcs); } +GList * +meta_kms_impl_device_copy_planes (MetaKmsImplDevice *impl_device) +{ + return g_list_copy (impl_device->planes); +} + +drmModePropertyPtr +meta_kms_impl_device_find_property (MetaKmsImplDevice *impl_device, + drmModeObjectProperties *props, + const char *prop_name, + int *out_idx) +{ + unsigned int i; + + meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl)); + + for (i = 0; i < props->count_props; i++) + { + drmModePropertyPtr prop; + + prop = drmModeGetProperty (impl_device->fd, props->props[i]); + if (!prop) + continue; + + if (strcmp (prop->name, prop_name) == 0) + { + *out_idx = i; + return prop; + } + + drmModeFreeProperty (prop); + } + + return NULL; +} + static void init_crtcs (MetaKmsImplDevice *impl_device, drmModeRes *drm_resources) @@ -74,6 +112,78 @@ init_crtcs (MetaKmsImplDevice *impl_device, impl_device->crtcs = g_list_reverse (impl_device->crtcs); } +static MetaKmsPlaneType +get_plane_type (MetaKmsImplDevice *impl_device, + drmModeObjectProperties *props) +{ + drmModePropertyPtr prop; + int idx; + + prop = meta_kms_impl_device_find_property (impl_device, props, "type", &idx); + if (!prop) + return FALSE; + drmModeFreeProperty (prop); + + switch (props->prop_values[idx]) + { + case DRM_PLANE_TYPE_PRIMARY: + return META_KMS_PLANE_TYPE_PRIMARY; + case DRM_PLANE_TYPE_CURSOR: + return META_KMS_PLANE_TYPE_CURSOR; + case DRM_PLANE_TYPE_OVERLAY: + return META_KMS_PLANE_TYPE_OVERLAY; + default: + g_warning ("Unhandled plane type %lu", props->prop_values[idx]); + return -1; + } +} + +static void +init_planes (MetaKmsImplDevice *impl_device) +{ + int fd = impl_device->fd; + drmModePlaneRes *drm_planes; + unsigned int i; + + drm_planes = drmModeGetPlaneResources (fd); + if (!drm_planes) + return; + + for (i = 0; i < drm_planes->count_planes; i++) + { + drmModePlane *drm_plane; + drmModeObjectProperties *props; + + drm_plane = drmModeGetPlane (fd, drm_planes->planes[i]); + if (!drm_plane) + continue; + + props = drmModeObjectGetProperties (fd, + drm_plane->plane_id, + DRM_MODE_OBJECT_PLANE); + if (props) + { + MetaKmsPlaneType plane_type; + + plane_type = get_plane_type (impl_device, props); + if (plane_type != -1) + { + MetaKmsPlane *plane; + + plane = meta_kms_plane_new (plane_type, + impl_device, + drm_plane, props); + + impl_device->planes = g_list_prepend (impl_device->planes, plane); + } + } + + g_clear_pointer (&props, drmModeFreeObjectProperties); + drmModeFreePlane (drm_plane); + } + impl_device->planes = g_list_reverse (impl_device->planes); +} + MetaKmsImplDevice * meta_kms_impl_device_new (MetaKmsDevice *device, MetaKmsImpl *impl, @@ -89,9 +199,12 @@ meta_kms_impl_device_new (MetaKmsDevice *device, impl_device->impl = impl; impl_device->fd = fd; + drmSetClientCap (fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + drm_resources = drmModeGetResources (fd); init_crtcs (impl_device, drm_resources); + init_planes (impl_device); drmModeFreeResources (drm_resources); @@ -130,6 +243,7 @@ meta_kms_impl_device_finalize (GObject *object) { MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (object); + g_list_free_full (impl_device->planes, g_object_unref); g_list_free_full (impl_device->crtcs, g_object_unref); G_OBJECT_CLASS (meta_kms_impl_device_parent_class)->finalize (object); diff --git a/src/backends/native/meta-kms-impl-device.h b/src/backends/native/meta-kms-impl-device.h index bbd481312..6ad45a887 100644 --- a/src/backends/native/meta-kms-impl-device.h +++ b/src/backends/native/meta-kms-impl-device.h @@ -22,6 +22,7 @@ #include #include +#include #include "backends/native/meta-kms-device.h" #include "backends/native/meta-kms-types.h" @@ -35,6 +36,13 @@ MetaKmsDevice * meta_kms_impl_device_get_device (MetaKmsImplDevice *impl_device) GList * meta_kms_impl_device_copy_crtcs (MetaKmsImplDevice *impl_device); +GList * meta_kms_impl_device_copy_planes (MetaKmsImplDevice *impl_device); + +drmModePropertyPtr meta_kms_impl_device_find_property (MetaKmsImplDevice *impl_device, + drmModeObjectProperties *props, + const char *prop_name, + int *idx); + int meta_kms_impl_device_get_fd (MetaKmsImplDevice *impl_device); int meta_kms_impl_device_leak_fd (MetaKmsImplDevice *impl_device); diff --git a/src/backends/native/meta-kms-plane.c b/src/backends/native/meta-kms-plane.c new file mode 100644 index 000000000..d4073d672 --- /dev/null +++ b/src/backends/native/meta-kms-plane.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2013-2019 Red Hat + * Copyright (C) 2018 DisplayLink (UK) Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "backends/native/meta-kms-plane.h" + +#include + +#include "backends/meta-monitor-transform.h" +#include "backends/native/meta-kms-crtc.h" +#include "backends/native/meta-kms-impl-device.h" + +struct _MetaKmsPlane +{ + GObject parent; + + MetaKmsPlaneType type; + uint32_t id; + + uint32_t possible_crtcs; + + uint32_t rotation_prop_id; + uint32_t rotation_map[META_MONITOR_N_TRANSFORMS]; + uint32_t all_hw_transforms; + + MetaKmsDevice *device; +}; + +G_DEFINE_TYPE (MetaKmsPlane, meta_kms_plane, G_TYPE_OBJECT) + +MetaKmsPlaneType +meta_kms_plane_get_plane_type (MetaKmsPlane *plane) +{ + return plane->type; +} + +gboolean +meta_kms_plane_is_transform_handled (MetaKmsPlane *plane, + MetaMonitorTransform transform) +{ + switch (transform) + { + case META_MONITOR_TRANSFORM_NORMAL: + case META_MONITOR_TRANSFORM_180: + case META_MONITOR_TRANSFORM_FLIPPED: + case META_MONITOR_TRANSFORM_FLIPPED_180: + break; + case META_MONITOR_TRANSFORM_90: + case META_MONITOR_TRANSFORM_270: + case META_MONITOR_TRANSFORM_FLIPPED_90: + case META_MONITOR_TRANSFORM_FLIPPED_270: + /* + * Blacklist these transforms as testing shows that they don't work + * anyway, e.g. due to the wrong buffer modifiers. They might as well be + * less optimal due to the complexity dealing with rotation at scan-out, + * potentially resulting in higher power consumption. + */ + return FALSE; + } + + return plane->all_hw_transforms & (1 << transform); +} + +gboolean +meta_kms_plane_is_usable_with (MetaKmsPlane *plane, + MetaKmsCrtc *crtc) +{ + return !!(plane->possible_crtcs & (1 << meta_kms_crtc_get_idx (crtc))); +} + +static void +parse_rotations (MetaKmsPlane *plane, + MetaKmsImplDevice *impl_device, + drmModePropertyPtr prop) +{ + int i; + + for (i = 0; i < prop->count_enums; i++) + { + MetaMonitorTransform transform = -1; + + if (strcmp (prop->enums[i].name, "rotate-0") == 0) + transform = META_MONITOR_TRANSFORM_NORMAL; + else if (strcmp (prop->enums[i].name, "rotate-90") == 0) + transform = META_MONITOR_TRANSFORM_90; + else if (strcmp (prop->enums[i].name, "rotate-180") == 0) + transform = META_MONITOR_TRANSFORM_180; + else if (strcmp (prop->enums[i].name, "rotate-270") == 0) + transform = META_MONITOR_TRANSFORM_270; + + if (transform != -1) + { + plane->all_hw_transforms |= 1 << transform; + plane->rotation_map[transform] = 1 << prop->enums[i].value; + } + } +} + +static void +init_rotations (MetaKmsPlane *plane, + MetaKmsImplDevice *impl_device, + drmModeObjectProperties *drm_plane_props) +{ + drmModePropertyPtr prop; + int idx; + + prop = meta_kms_impl_device_find_property (impl_device, drm_plane_props, + "rotation", &idx); + if (prop) + { + plane->rotation_prop_id = drm_plane_props->props[idx]; + parse_rotations (plane, impl_device, prop); + drmModeFreeProperty (prop); + } +} + +MetaKmsPlane * +meta_kms_plane_new (MetaKmsPlaneType type, + MetaKmsImplDevice *impl_device, + drmModePlane *drm_plane, + drmModeObjectProperties *drm_plane_props) +{ + MetaKmsPlane *plane; + + plane = g_object_new (META_TYPE_KMS_PLANE, NULL); + plane->type = type; + plane->id = drm_plane->plane_id; + plane->possible_crtcs = drm_plane->possible_crtcs; + plane->device = meta_kms_impl_device_get_device (impl_device); + + init_rotations (plane, impl_device, drm_plane_props); + + return plane; +} + +static void +meta_kms_plane_init (MetaKmsPlane *plane) +{ +} + +static void +meta_kms_plane_class_init (MetaKmsPlaneClass *klass) +{ +} diff --git a/src/backends/native/meta-kms-plane.h b/src/backends/native/meta-kms-plane.h new file mode 100644 index 000000000..76020d8d9 --- /dev/null +++ b/src/backends/native/meta-kms-plane.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_KMS_PLANE_H +#define META_KMS_PLANE_H + +#include +#include +#include + +#include "backends/native/meta-kms-types.h" +#include "backends/meta-monitor-transform.h" + +typedef enum _MetaKmsPlaneType +{ + META_KMS_PLANE_TYPE_PRIMARY, + META_KMS_PLANE_TYPE_CURSOR, + META_KMS_PLANE_TYPE_OVERLAY, +} MetaKmsPlaneType; + +#define META_TYPE_KMS_PLANE meta_kms_plane_get_type () +G_DECLARE_FINAL_TYPE (MetaKmsPlane, meta_kms_plane, + META, KMS_PLANE, GObject) + +MetaKmsPlane * meta_kms_plane_new (MetaKmsPlaneType type, + MetaKmsImplDevice *impl_device, + drmModePlane *drm_plane, + drmModeObjectProperties *drm_plane_props); + +MetaKmsPlaneType meta_kms_plane_get_plane_type (MetaKmsPlane *plane); + +gboolean meta_kms_plane_is_transform_handled (MetaKmsPlane *plane, + MetaMonitorTransform transform); + +gboolean meta_kms_plane_is_usable_with (MetaKmsPlane *plane, + MetaKmsCrtc *crtc); + +#endif /* META_KMS_PLANE_H */ diff --git a/src/meson.build b/src/meson.build index 73fc2751b..fd1b93ecb 100644 --- a/src/meson.build +++ b/src/meson.build @@ -606,6 +606,8 @@ 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-plane.c', + 'backends/native/meta-kms-plane.h', 'backends/native/meta-kms-private.h', 'backends/native/meta-kms-types.h', 'backends/native/meta-kms.c',