Commit d84c7269 authored by Jonas Ådahl's avatar Jonas Ådahl Committed by Georges Basile Stavracas Neto

crtc/kms: Use MetaKmsPlane to check supported rotations and formats

Instead of manually retrieving supported transforms and formats from the
primary plane of the CRTC, use the MetaKmsPlane abstraction to find the
primary plane of the CRTC and check compatibility using the
MetaKmsPlane API. This removes the last user of direct KMS API usage
except for applying configuration.

GNOME/mutter#548
GNOME/mutter!525
parent aba68931
......@@ -29,6 +29,8 @@
#include "backends/meta-backend-private.h"
#include "backends/native/meta-gpu-kms.h"
#include "backends/native/meta-kms-device.h"
#include "backends/native/meta-kms-plane.h"
/* added in libdrm 2.4.95 */
#ifndef DRM_FORMAT_INVALID
......@@ -41,17 +43,10 @@ typedef struct _MetaCrtcKms
{
MetaKmsCrtc *kms_crtc;
uint32_t primary_plane_id;
uint32_t rotation_prop_id;
uint32_t rotation_map[META_MONITOR_N_TRANSFORMS];
uint32_t all_hw_transforms;
/*
* primary plane's supported formats and maybe modifiers
* key: GUINT_TO_POINTER (format)
* value: owned GArray* (uint64_t modifier), or NULL
*/
GHashTable *formats_modifiers;
MetaKmsPlane *primary_plane;
} MetaCrtcKms;
/**
......@@ -93,10 +88,11 @@ meta_crtc_kms_is_transform_handled (MetaCrtc *crtc,
{
MetaCrtcKms *crtc_kms = crtc->driver_private;
if ((1 << transform) & crtc_kms->all_hw_transforms)
return TRUE;
else
if (!crtc_kms->primary_plane)
return FALSE;
return meta_kms_plane_is_transform_handled (crtc_kms->primary_plane,
transform);
}
void
......@@ -110,28 +106,18 @@ meta_crtc_kms_apply_transform (MetaCrtc *crtc)
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
if (crtc_kms->all_hw_transforms & (1 << crtc->transform))
hw_transform = crtc->transform;
else
hw_transform = crtc->transform;
if (!meta_crtc_kms_is_transform_handled (crtc, hw_transform))
hw_transform = META_MONITOR_TRANSFORM_NORMAL;
if (!meta_crtc_kms_is_transform_handled (crtc, META_MONITOR_TRANSFORM_NORMAL))
if (!meta_crtc_kms_is_transform_handled (crtc, hw_transform))
return;
if (drmModeObjectSetProperty (kms_fd,
crtc_kms->primary_plane_id,
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);
/*
* Blacklist this HW transform, we want to fallback to our
* fallbacks in this case.
*/
crtc_kms->all_hw_transforms &= ~(1 << hw_transform);
}
g_warning ("Failed to apply DRM plane transform %d: %m", hw_transform);
}
static int
......@@ -194,8 +180,8 @@ meta_crtc_kms_get_modifiers (MetaCrtc *crtc,
{
MetaCrtcKms *crtc_kms = crtc->driver_private;
return g_hash_table_lookup (crtc_kms->formats_modifiers,
GUINT_TO_POINTER (format));
return meta_kms_plane_get_modifiers_for_format (crtc_kms->primary_plane,
format);
}
/**
......@@ -210,24 +196,8 @@ GArray *
meta_crtc_kms_copy_drm_format_list (MetaCrtc *crtc)
{
MetaCrtcKms *crtc_kms = crtc->driver_private;
GArray *formats;
GHashTableIter it;
gpointer key;
unsigned int n_formats_modifiers;
n_formats_modifiers = g_hash_table_size (crtc_kms->formats_modifiers);
formats = g_array_sized_new (FALSE,
FALSE,
sizeof (uint32_t),
n_formats_modifiers);
g_hash_table_iter_init (&it, crtc_kms->formats_modifiers);
while (g_hash_table_iter_next (&it, &key, NULL))
{
uint32_t drm_format = GPOINTER_TO_UINT (key);
g_array_append_val (formats, drm_format);
}
return formats;
return meta_kms_plane_copy_drm_format_list (crtc_kms->primary_plane);
}
/**
......@@ -243,124 +213,8 @@ meta_crtc_kms_supports_format (MetaCrtc *crtc,
{
MetaCrtcKms *crtc_kms = crtc->driver_private;
return g_hash_table_lookup_extended (crtc_kms->formats_modifiers,
GUINT_TO_POINTER (drm_format),
NULL,
NULL);
}
static inline uint32_t *
formats_ptr (struct drm_format_modifier_blob *blob)
{
return (uint32_t *) (((char *) blob) + blob->formats_offset);
}
static inline struct drm_format_modifier *
modifiers_ptr (struct drm_format_modifier_blob *blob)
{
return (struct drm_format_modifier *) (((char *) blob) +
blob->modifiers_offset);
}
static void
free_modifier_array (GArray *array)
{
if (!array)
return;
g_array_free (array, TRUE);
}
/*
* In case the DRM driver does not expose a format list for the
* primary plane (does not support universal planes nor
* IN_FORMATS property), hardcode something that is probably supported.
*/
static const uint32_t drm_default_formats[] =
{
DRM_FORMAT_XRGB8888 /* The format everything should always support by convention */,
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
DRM_FORMAT_XBGR8888 /* OpenGL GL_RGBA, GL_UNSIGNED_BYTE format, hopefully supported */
#endif
};
static void
set_formats_from_array (MetaCrtc *crtc,
const uint32_t *formats,
size_t n_formats)
{
MetaCrtcKms *crtc_kms = crtc->driver_private;
size_t i;
for (i = 0; i < n_formats; i++)
{
g_hash_table_insert (crtc_kms->formats_modifiers,
GUINT_TO_POINTER (formats[i]), NULL);
}
}
static void
parse_formats (MetaCrtc *crtc,
int kms_fd,
uint32_t blob_id)
{
MetaCrtcKms *crtc_kms = crtc->driver_private;
drmModePropertyBlobPtr blob;
struct drm_format_modifier_blob *blob_fmt;
uint32_t *formats;
struct drm_format_modifier *modifiers;
unsigned int fmt_i, mod_i;
g_return_if_fail (g_hash_table_size (crtc_kms->formats_modifiers) == 0);
if (blob_id == 0)
return;
blob = drmModeGetPropertyBlob (kms_fd, blob_id);
if (!blob)
return;
if (blob->length < sizeof (struct drm_format_modifier_blob))
{
drmModeFreePropertyBlob (blob);
return;
}
blob_fmt = blob->data;
formats = formats_ptr (blob_fmt);
modifiers = modifiers_ptr (blob_fmt);
for (fmt_i = 0; fmt_i < blob_fmt->count_formats; fmt_i++)
{
GArray *mod_tmp = g_array_new (FALSE, FALSE, sizeof (uint64_t));
for (mod_i = 0; mod_i < blob_fmt->count_modifiers; mod_i++)
{
struct drm_format_modifier *modifier = &modifiers[mod_i];
/* The modifier advertisement blob is partitioned into groups of
* 64 formats. */
if (fmt_i < modifier->offset || fmt_i > modifier->offset + 63)
continue;
if (!(modifier->formats & (1 << (fmt_i - modifier->offset))))
continue;
g_array_append_val (mod_tmp, modifier->modifier);
}
if (mod_tmp->len == 0)
{
free_modifier_array (mod_tmp);
mod_tmp = NULL;
}
g_hash_table_insert (crtc_kms->formats_modifiers,
GUINT_TO_POINTER (formats[fmt_i]), mod_tmp);
}
drmModeFreePropertyBlob (blob);
return meta_kms_plane_is_format_supported (crtc_kms->primary_plane,
drm_format);
}
static void
......@@ -384,28 +238,10 @@ parse_transforms (MetaCrtc *crtc,
transform = META_MONITOR_TRANSFORM_270;
if (transform != -1)
{
crtc_kms->all_hw_transforms |= 1 << transform;
crtc_kms->rotation_map[transform] = 1 << prop->enums[i].value;
}
crtc_kms->rotation_map[transform] = 1 << prop->enums[i].value;
}
}
static gboolean
is_primary_plane (MetaGpu *gpu,
drmModeObjectPropertiesPtr props)
{
drmModePropertyPtr prop;
int idx;
idx = find_property_index (gpu, props, "type", &prop);
if (idx < 0)
return FALSE;
drmModeFreeProperty (prop);
return props->prop_values[idx] == DRM_PLANE_TYPE_PRIMARY;
}
static void
init_crtc_rotations (MetaCrtc *crtc,
MetaGpu *gpu)
......@@ -413,91 +249,35 @@ init_crtc_rotations (MetaCrtc *crtc,
MetaCrtcKms *crtc_kms = crtc->driver_private;
MetaGpuKms *gpu_kms = META_GPU_KMS (gpu);
int kms_fd;
drmModeObjectPropertiesPtr props;
drmModePlaneRes *planes;
uint32_t primary_plane_id;
drmModePlane *drm_plane;
unsigned int i;
int crtc_idx;
drmModeObjectPropertiesPtr props;
drmModePropertyPtr prop;
int rotation_idx;
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
planes = drmModeGetPlaneResources (kms_fd);
if (planes == NULL)
return;
crtc_idx = meta_kms_crtc_get_idx (crtc_kms->kms_crtc);
for (i = 0; i < planes->count_planes; i++)
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)
{
drmModePropertyPtr prop;
drm_plane = drmModeGetPlane (kms_fd, planes->planes[i]);
if (!drm_plane)
continue;
if ((drm_plane->possible_crtcs & (1 << crtc_idx)))
{
props = drmModeObjectGetProperties (kms_fd,
drm_plane->plane_id,
DRM_MODE_OBJECT_PLANE);
if (props && is_primary_plane (gpu, props))
{
int rotation_idx, fmts_idx;
crtc_kms->primary_plane_id = drm_plane->plane_id;
rotation_idx = find_property_index (gpu, props,
"rotation", &prop);
if (rotation_idx >= 0)
{
crtc_kms->rotation_prop_id = props->props[rotation_idx];
parse_transforms (crtc, prop);
drmModeFreeProperty (prop);
}
fmts_idx = find_property_index (gpu, props,
"IN_FORMATS", &prop);
if (fmts_idx >= 0)
{
parse_formats (crtc, kms_fd, props->prop_values[fmts_idx]);
drmModeFreeProperty (prop);
}
/* fall back to universal plane formats without modifiers */
if (g_hash_table_size (crtc_kms->formats_modifiers) == 0)
{
set_formats_from_array (crtc,
drm_plane->formats,
drm_plane->count_formats);
}
}
if (props)
drmModeFreeObjectProperties (props);
}
drmModeFreePlane (drm_plane);
crtc_kms->rotation_prop_id = props->props[rotation_idx];
parse_transforms (crtc, prop);
drmModeFreeProperty (prop);
}
crtc->all_transforms |= crtc_kms->all_hw_transforms;
drmModeFreePlaneResources (planes);
/* final formats fallback to something hardcoded */
if (g_hash_table_size (crtc_kms->formats_modifiers) == 0)
{
set_formats_from_array (crtc,
drm_default_formats,
G_N_ELEMENTS (drm_default_formats));
}
drmModeFreeObjectProperties (props);
drmModeFreePlane (drm_plane);
}
static void
meta_crtc_destroy_notify (MetaCrtc *crtc)
{
MetaCrtcKms *crtc_kms = crtc->driver_private;
g_hash_table_destroy (crtc_kms->formats_modifiers);
g_free (crtc->driver_private);
}
......@@ -506,10 +286,15 @@ meta_create_kms_crtc (MetaGpuKms *gpu_kms,
MetaKmsCrtc *kms_crtc)
{
MetaGpu *gpu = META_GPU (gpu_kms);
MetaKmsDevice *kms_device;
MetaCrtc *crtc;
MetaCrtcKms *crtc_kms;
MetaKmsPlane *primary_plane;
const MetaKmsCrtcState *crtc_state;
kms_device = meta_gpu_kms_get_kms_device (gpu_kms);
primary_plane = meta_kms_device_get_primary_plane_for (kms_device,
kms_crtc);
crtc_state = meta_kms_crtc_get_current_state (kms_crtc);
crtc = g_object_new (META_TYPE_CRTC, NULL);
......@@ -538,12 +323,7 @@ meta_create_kms_crtc (MetaGpuKms *gpu_kms,
crtc_kms = g_new0 (MetaCrtcKms, 1);
crtc_kms->kms_crtc = kms_crtc;
crtc_kms->formats_modifiers =
g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL,
(GDestroyNotify) free_modifier_array);
crtc_kms->primary_plane = primary_plane;
crtc->driver_private = crtc_kms;
crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify;
......
......@@ -381,6 +381,12 @@ meta_gpu_kms_wait_for_flip (MetaGpuKms *gpu_kms,
return TRUE;
}
MetaKmsDevice *
meta_gpu_kms_get_kms_device (MetaGpuKms *gpu_kms)
{
return gpu_kms->kms_device;
}
int
meta_gpu_kms_get_fd (MetaGpuKms *gpu_kms)
{
......
......@@ -64,6 +64,8 @@ gboolean meta_gpu_kms_flip_crtc (MetaGpuKms *gpu_kms,
gboolean meta_gpu_kms_wait_for_flip (MetaGpuKms *gpu_kms,
GError **error);
MetaKmsDevice * meta_gpu_kms_get_kms_device (MetaGpuKms *gpu_kms);
int meta_gpu_kms_get_fd (MetaGpuKms *gpu_kms);
uint32_t meta_gpu_kms_get_id (MetaGpuKms *gpu_kms);
......
......@@ -25,6 +25,7 @@
#include "backends/native/meta-backend-native.h"
#include "backends/native/meta-kms-impl-device.h"
#include "backends/native/meta-kms-impl.h"
#include "backends/native/meta-kms-plane.h"
#include "backends/native/meta-kms-private.h"
struct _MetaKmsDevice
......@@ -81,6 +82,32 @@ meta_kms_device_get_crtcs (MetaKmsDevice *device)
return device->crtcs;
}
static GList *
meta_kms_device_get_planes (MetaKmsDevice *device)
{
return device->planes;
}
MetaKmsPlane *
meta_kms_device_get_primary_plane_for (MetaKmsDevice *device,
MetaKmsCrtc *crtc)
{
GList *l;
for (l = meta_kms_device_get_planes (device); l; l = l->next)
{
MetaKmsPlane *plane = l->data;
if (meta_kms_plane_get_plane_type (plane) != META_KMS_PLANE_TYPE_PRIMARY)
continue;
if (meta_kms_plane_is_usable_with (plane, crtc))
return plane;
}
return NULL;
}
typedef struct _CreateImplDeviceData
{
MetaKmsDevice *device;
......
......@@ -39,6 +39,9 @@ GList * meta_kms_device_get_connectors (MetaKmsDevice *device);
GList * meta_kms_device_get_crtcs (MetaKmsDevice *device);
MetaKmsPlane * meta_kms_device_get_primary_plane_for (MetaKmsDevice *device,
MetaKmsCrtc *crtc);
MetaKmsDevice * meta_kms_device_new (MetaKms *kms,
const char *path,
MetaKmsDeviceFlag flags,
......
......@@ -41,11 +41,24 @@ struct _MetaKmsPlane
uint32_t rotation_map[META_MONITOR_N_TRANSFORMS];
uint32_t all_hw_transforms;
/*
* primary plane's supported formats and maybe modifiers
* key: GUINT_TO_POINTER (format)
* value: owned GArray* (uint64_t modifier), or NULL
*/
GHashTable *formats_modifiers;
MetaKmsDevice *device;
};
G_DEFINE_TYPE (MetaKmsPlane, meta_kms_plane, G_TYPE_OBJECT)
uint32_t
meta_kms_plane_get_id (MetaKmsPlane *plane)
{
return plane->id;
}
MetaKmsPlaneType
meta_kms_plane_get_plane_type (MetaKmsPlane *plane)
{
......@@ -75,10 +88,49 @@ meta_kms_plane_is_transform_handled (MetaKmsPlane *plane,
*/
return FALSE;
}
return plane->all_hw_transforms & (1 << transform);
}
GArray *
meta_kms_plane_get_modifiers_for_format (MetaKmsPlane *plane,
uint32_t format)
{
return g_hash_table_lookup (plane->formats_modifiers,
GUINT_TO_POINTER (format));
}
GArray *
meta_kms_plane_copy_drm_format_list (MetaKmsPlane *plane)
{
GArray *formats;
GHashTableIter it;
gpointer key;
unsigned int n_formats_modifiers;
n_formats_modifiers = g_hash_table_size (plane->formats_modifiers);
formats = g_array_sized_new (FALSE, FALSE,
sizeof (uint32_t),
n_formats_modifiers);
g_hash_table_iter_init (&it, plane->formats_modifiers);
while (g_hash_table_iter_next (&it, &key, NULL))
{
uint32_t drm_format = GPOINTER_TO_UINT (key);
g_array_append_val (formats, drm_format);
}
return formats;
}
gboolean
meta_kms_plane_is_format_supported (MetaKmsPlane *plane,
uint32_t drm_format)
{
return g_hash_table_lookup_extended (plane->formats_modifiers,
GUINT_TO_POINTER (drm_format),
NULL, NULL);
}
gboolean
meta_kms_plane_is_usable_with (MetaKmsPlane *plane,
MetaKmsCrtc *crtc)
......@@ -132,6 +184,122 @@ init_rotations (MetaKmsPlane *plane,
}
}
static inline uint32_t *
drm_formats_ptr (struct drm_format_modifier_blob *blob)
{
return (uint32_t *) (((char *) blob) + blob->formats_offset);
}
static inline struct drm_format_modifier *
drm_modifiers_ptr (struct drm_format_modifier_blob *blob)
{
return (struct drm_format_modifier *) (((char *) blob) +
blob->modifiers_offset);
}
static void
free_modifier_array (GArray *array)
{
if (!array)
return;
g_array_free (array, TRUE);
}
static void
parse_formats (MetaKmsPlane *plane,
MetaKmsImplDevice *impl_device,
uint32_t blob_id)
{
int fd;
drmModePropertyBlobPtr blob;
struct drm_format_modifier_blob *blob_fmt;
uint32_t *formats;
struct drm_format_modifier *drm_modifiers;
unsigned int fmt_i, mod_i;
g_return_if_fail (g_hash_table_size (plane->formats_modifiers) == 0);
if (blob_id == 0)
return;
fd = meta_kms_impl_device_get_fd (impl_device);
blob = drmModeGetPropertyBlob (fd, blob_id);
if (!blob)
return;
if (blob->length < sizeof (struct drm_format_modifier_blob))
{
drmModeFreePropertyBlob (blob);
return;
}
blob_fmt = blob->data;
formats = drm_formats_ptr (blob_fmt);
drm_modifiers = drm_modifiers_ptr (blob_fmt);
for (fmt_i = 0; fmt_i < blob_fmt->count_formats; fmt_i++)
{
GArray *modifiers = g_array_new (FALSE, FALSE, sizeof (uint64_t));
for (mod_i = 0; mod_i < blob_fmt->count_modifiers; mod_i++)
{
struct drm_format_modifier *drm_modifier = &drm_modifiers[mod_i];
/*
* The modifier advertisement blob is partitioned into groups of
* 64 formats.
*/
if (fmt_i < drm_modifier->offset || fmt_i > drm_modifier->offset + 63)
continue;
if (!(drm_modifier->formats & (1 << (fmt_i - drm_modifier->offset))))
continue;
g_array_append_val (modifiers, drm_modifier->modifier);
}
if (modifiers->len == 0)
{
free_modifier_array (modifiers);
modifiers = NULL;
}