native: Implement DRM-based crtc rotation

We can know the rotation modes supported by the driver, so
export these as our supported modes, and ensure these modes
are honored on the CRTC primary plane upon apply_configuration().

It is worth noting however that not all hardware will be
capable of supporting all rotation modes (in fact, most of
them won't). A driver independent solution should be in
place to back up the rotation modes unsupported by the
drivers, so this is still a partial solution.

The cursor renderer has also been changed to default to
software-based rendering anytime the cursor enters a
rotated CRTC. Another solution would be actually rotating
the DRM cursor planes, but then it requires applying rotation on
these per-CRTC, and actually transforming the pointer position by
the output matrix. This brings marginal gains, so we use the
"sw" rendered cursor, which will be transformed together with
the primary plane.

https://bugzilla.gnome.org/show_bug.cgi?id=745079
This commit is contained in:
Carlos Garnacho 2015-12-18 12:16:59 +01:00
parent 3a2cd3389a
commit efef0c993b
2 changed files with 174 additions and 0 deletions

View File

@ -273,6 +273,32 @@ has_valid_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite)
return FALSE; return FALSE;
} }
static gboolean
cursor_over_transformed_crtc (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
MetaMonitorManager *monitors;
MetaCRTC *crtcs;
unsigned int i, n_crtcs;
MetaRectangle rect;
monitors = meta_monitor_manager_get ();
meta_monitor_manager_get_resources (monitors, NULL, NULL,
&crtcs, &n_crtcs, NULL, NULL);
rect = meta_cursor_renderer_calculate_rect (renderer, cursor_sprite);
for (i = 0; i < n_crtcs; i++)
{
if (!meta_rectangle_overlap (&rect, &crtcs[i].rect))
continue;
if (crtcs[i].transform != META_MONITOR_TRANSFORM_NORMAL)
return TRUE;
}
return FALSE;
}
static gboolean static gboolean
should_have_hw_cursor (MetaCursorRenderer *renderer, should_have_hw_cursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite) MetaCursorSprite *cursor_sprite)
@ -282,6 +308,9 @@ should_have_hw_cursor (MetaCursorRenderer *renderer,
if (!cursor_sprite) if (!cursor_sprite)
return FALSE; return FALSE;
if (cursor_over_transformed_crtc (renderer, cursor_sprite))
return FALSE;
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite); texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
if (!texture) if (!texture)
return FALSE; return FALSE;

View File

@ -42,6 +42,8 @@
#include <gudev/gudev.h> #include <gudev/gudev.h>
#define ALL_TRANSFORMS (META_MONITOR_TRANSFORM_FLIPPED_270 + 1)
typedef struct { typedef struct {
drmModeConnector *connector; drmModeConnector *connector;
@ -66,6 +68,9 @@ typedef struct {
uint32_t underscan_prop_id; uint32_t underscan_prop_id;
uint32_t underscan_hborder_prop_id; uint32_t underscan_hborder_prop_id;
uint32_t underscan_vborder_prop_id; uint32_t underscan_vborder_prop_id;
uint32_t primary_plane_id;
uint32_t rotation_prop_id;
uint32_t rotation_map[ALL_TRANSFORMS];
} MetaCRTCKms; } MetaCRTCKms;
struct _MetaMonitorManagerKms struct _MetaMonitorManagerKms
@ -429,6 +434,135 @@ get_output_scale (MetaMonitorManager *manager,
return compute_scale (output); return compute_scale (output);
} }
static int
find_property_index (MetaMonitorManager *manager,
drmModeObjectPropertiesPtr props,
const gchar *prop_name,
drmModePropertyPtr *found)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
unsigned int i;
for (i = 0; i < props->count_props; i++)
{
drmModePropertyPtr prop;
prop = drmModeGetProperty (manager_kms->fd, props->props[i]);
if (!prop)
continue;
if (strcmp (prop->name, prop_name) == 0)
{
*found = prop;
return i;
}
drmModeFreeProperty (prop);
}
return -1;
}
static void
parse_transforms (MetaMonitorManager *manager,
drmModePropertyPtr prop,
MetaCRTC *crtc)
{
MetaCRTCKms *crtc_kms = crtc->driver_private;
int i;
for (i = 0; i < prop->count_enums; i++)
{
int cur = -1;
if (strcmp (prop->enums[i].name, "rotate-0") == 0)
cur = META_MONITOR_TRANSFORM_NORMAL;
else if (strcmp (prop->enums[i].name, "rotate-90") == 0)
cur = META_MONITOR_TRANSFORM_90;
else if (strcmp (prop->enums[i].name, "rotate-180") == 0)
cur = META_MONITOR_TRANSFORM_180;
else if (strcmp (prop->enums[i].name, "rotate-270") == 0)
cur = META_MONITOR_TRANSFORM_270;
if (cur != -1)
{
crtc->all_transforms |= 1 << cur;
crtc_kms->rotation_map[cur] = 1 << prop->enums[i].value;
}
}
}
static gboolean
is_primary_plane (MetaMonitorManager *manager,
drmModeObjectPropertiesPtr props)
{
drmModePropertyPtr prop;
int idx;
idx = find_property_index (manager, props, "type", &prop);
if (idx < 0)
return FALSE;
drmModeFreeProperty (prop);
return props->prop_values[idx] == DRM_PLANE_TYPE_PRIMARY;
}
static void
init_crtc_rotations (MetaMonitorManager *manager,
MetaCRTC *crtc,
unsigned int idx)
{
MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager);
drmModeObjectPropertiesPtr props;
drmModePlaneRes *planes;
drmModePlane *drm_plane;
MetaCRTCKms *crtc_kms;
unsigned int i;
crtc_kms = crtc->driver_private;
planes = drmModeGetPlaneResources(manager_kms->fd);
if (planes == NULL)
return;
for (i = 0; i < planes->count_planes; i++)
{
drmModePropertyPtr prop;
drm_plane = drmModeGetPlane (manager_kms->fd, planes->planes[i]);
if (!drm_plane)
continue;
if ((drm_plane->possible_crtcs & (1 << idx)))
{
props = drmModeObjectGetProperties (manager_kms->fd,
drm_plane->plane_id,
DRM_MODE_OBJECT_PLANE);
if (props && is_primary_plane (manager, props))
{
int rotation_idx;
crtc_kms->primary_plane_id = drm_plane->plane_id;
rotation_idx = find_property_index (manager, props, "rotation", &prop);
if (rotation_idx >= 0)
{
crtc_kms->rotation_prop_id = props->props[rotation_idx];
parse_transforms (manager, prop, crtc);
drmModeFreeProperty (prop);
}
}
if (props)
drmModeFreeObjectProperties (props);
}
drmModeFreePlane (drm_plane);
}
}
static void static void
meta_monitor_manager_kms_read_current (MetaMonitorManager *manager) meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
{ {
@ -556,6 +690,7 @@ meta_monitor_manager_kms_read_current (MetaMonitorManager *manager)
meta_crtc->driver_private = g_new0 (MetaCRTCKms, 1); meta_crtc->driver_private = g_new0 (MetaCRTCKms, 1);
meta_crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify; meta_crtc->driver_notify = (GDestroyNotify) meta_crtc_destroy_notify;
find_crtc_properties (manager_kms, meta_crtc); find_crtc_properties (manager_kms, meta_crtc);
init_crtc_rotations (manager, meta_crtc, i);
drmModeFreeCrtc (crtc); drmModeFreeCrtc (crtc);
} }
@ -938,6 +1073,7 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
{ {
MetaCRTCInfo *crtc_info = crtcs[i]; MetaCRTCInfo *crtc_info = crtcs[i];
MetaCRTC *crtc = crtc_info->crtc; MetaCRTC *crtc = crtc_info->crtc;
MetaCRTCKms *crtc_kms = crtc->driver_private;
CoglKmsCrtc *cogl_crtc; CoglKmsCrtc *cogl_crtc;
crtc->is_dirty = TRUE; crtc->is_dirty = TRUE;
@ -1010,6 +1146,13 @@ meta_monitor_manager_kms_apply_configuration (MetaMonitorManager *manager,
crtc->current_mode = mode; crtc->current_mode = mode;
crtc->transform = crtc_info->transform; crtc->transform = crtc_info->transform;
} }
if (crtc->all_transforms & (1 << crtc->transform))
drmModeObjectSetProperty (manager_kms->fd,
crtc_kms->primary_plane_id,
DRM_MODE_OBJECT_PLANE,
crtc_kms->rotation_prop_id,
crtc_kms->rotation_map[crtc->transform]);
} }
/* Disable CRTCs not mentioned in the list (they have is_dirty == FALSE, /* Disable CRTCs not mentioned in the list (they have is_dirty == FALSE,
@ -1162,6 +1305,8 @@ meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer); manager_kms->fd = cogl_kms_renderer_get_kms_fd (cogl_renderer);
drmSetClientCap (manager_kms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
const char *subsystems[2] = { "drm", NULL }; const char *subsystems[2] = { "drm", NULL };
manager_kms->udev = g_udev_client_new (subsystems); manager_kms->udev = g_udev_client_new (subsystems);
g_signal_connect (manager_kms->udev, "uevent", g_signal_connect (manager_kms->udev, "uevent",