sna: Support native primary plane rotations

Use the display hardware for simple rotations, when exported through the
rotation property on the CRTC.

As the kernel support is not yet merged upstream, the feature is hidden
behind --enable-rotation.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2014-02-12 11:33:45 +00:00
parent 3b43630f55
commit 607737cc47
3 changed files with 159 additions and 4 deletions

View File

@ -578,6 +578,17 @@ if test "x$CREATE2" = "xyes"; then
xp_msg="$xp_msg create2"
fi
AC_ARG_ENABLE(rotation,
AS_HELP_STRING([--enable-rotation],
[Enable use of native rotations (experimental) [default=no]]),
[ROTATION="$enableval"],
[ROTATION="no"])
AM_CONDITIONAL(USE_ROTATION, test "x$ROTATION" = "xyes")
if test "x$ROTATION" = "xyes"; then
AC_DEFINE(USE_ROTATION,1,[Assume "rotation" support])
xp_msg="$xp_msg rotation"
fi
AC_ARG_ENABLE(userptr,
AS_HELP_STRING([--enable-userptr],
[Enable use of userptr (experimental) [default=no]]),

View File

@ -1537,6 +1537,25 @@ gen5_composite_picture(struct sna *sna,
return sna_render_picture_extract(sna, picture, channel,
x, y, w, h, dst_x, dst_y);
DBG(("%s: pixmap, repeat=%d, filter=%d, transform?=%d [affine? %d], format=%08x\n",
__FUNCTION__,
channel->repeat, channel->filter,
channel->transform != NULL, channel->is_affine,
channel->pict_format));
if (channel->transform) {
DBG(("%s: transform=[%f %f %f, %f %f %f, %f %f %f]\n",
__FUNCTION__,
channel->transform->matrix[0][0] / 65536.,
channel->transform->matrix[0][1] / 65536.,
channel->transform->matrix[0][2] / 65536.,
channel->transform->matrix[1][0] / 65536.,
channel->transform->matrix[1][1] / 65536.,
channel->transform->matrix[1][2] / 65536.,
channel->transform->matrix[2][0] / 65536.,
channel->transform->matrix[2][1] / 65536.,
channel->transform->matrix[2][2] / 65536.));
}
return sna_render_pixmap_bo(sna, channel, pixmap,
x, y, w, h, dst_x, dst_y);
}

View File

@ -105,6 +105,10 @@ struct sna_crtc {
uint8_t id;
uint8_t pipe;
uint8_t plane;
uint32_t rotation_id;
uint32_t supported_rotations;
uint32_t rotation, last_rotation;
};
struct sna_property {
@ -842,10 +846,35 @@ sna_crtc_apply(xf86CrtcPtr crtc)
int output_count = 0;
int i;
DBG(("%s\n", __FUNCTION__));
DBG(("%s CRTC:%d [pipe=%d]\n", __FUNCTION__, sna_crtc->id, sna_crtc->pipe));
assert(config->num_output < ARRAY_SIZE(output_ids));
if (sna_crtc->rotation != sna_crtc->last_rotation) {
assert(sna_crtc->rotation_id);
DBG(("%s: disabling CRTC:%d [pipe=%d] before changing rotation from %x to %x\n",
__FUNCTION__, sna_crtc->id, sna_crtc->pipe,
sna_crtc->last_rotation, sna_crtc->rotation));
memset(&arg, 0, sizeof(arg));
arg.crtc_id = sna_crtc->id;
(void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg);
if (drmModeObjectSetProperty(sna->kgem.fd, sna_crtc->id,
DRM_MODE_OBJECT_CRTC,
sna_crtc->rotation_id,
sna_crtc->rotation)) {
ERR(("%s: set-rotation failed (rotation-id=%d, rotation=%d) on CRTC:%d [pipe=%d], errno=%d\n",
__FUNCTION__, sna_crtc->rotation_id, sna_crtc->rotation, sna_crtc->id, sna_crtc->pipe, errno));
return false;
}
sna_crtc->last_rotation = sna_crtc->rotation;
DBG(("%s: CRTC:%d [pipe=%d] rotation set to %x\n",
__FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->rotation));
}
for (i = 0; i < config->num_output; i++) {
xf86OutputPtr output = config->output[i];
@ -1101,6 +1130,15 @@ sna_crtc_disable(xf86CrtcPtr crtc)
arg.crtc_id = sna_crtc->id;
(void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg);
if (sna_crtc->last_rotation != RR_Rotate_0) {
assert(sna_crtc->rotation_id);
(void)drmModeObjectSetProperty(sna->kgem.fd, sna_crtc->id,
DRM_MODE_OBJECT_CRTC,
sna_crtc->rotation_id,
RR_Rotate_0);
sna_crtc->last_rotation = RR_Rotate_0;
}
sna_crtc_disable_shadow(sna, sna_crtc);
if (sna_crtc->bo) {
@ -1333,8 +1371,19 @@ static bool use_shadow(struct sna *sna, xf86CrtcPtr crtc)
&crtc_to_fb,
&f_crtc_to_fb,
&f_fb_to_crtc)) {
DBG(("%s: RandR transform present\n", __FUNCTION__));
return true;
bool needs_transform = true;
DBG(("%s: natively supported rotation? rotation=%x & supported=%x == %d\n",
__FUNCTION__, crtc->rotation, to_sna_crtc(crtc)->supported_rotations,
!!(crtc->rotation & to_sna_crtc(crtc)->supported_rotations)));
if (to_sna_crtc(crtc)->supported_rotations & crtc->rotation)
needs_transform = RRTransformCompute(crtc->x, crtc->y,
crtc->mode.HDisplay, crtc->mode.VDisplay,
RR_Rotate_0, transform,
NULL, NULL, NULL);
if (needs_transform) {
DBG(("%s: RandR transform present\n", __FUNCTION__));
return true;
}
}
/* And finally check that it is entirely visible */
@ -1365,6 +1414,8 @@ static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
struct kgem_bo *bo;
sna_crtc->transform = false;
sna_crtc->rotation = RR_Rotate_0;
if (sna_crtc->scanout_pixmap) {
DBG(("%s: attaching to scanout pixmap\n", __FUNCTION__));
@ -1468,6 +1519,7 @@ static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
return NULL;
assert(!sna_crtc->shadow);
sna_crtc->rotation = crtc->rotation;
return kgem_bo_reference(bo);
}
}
@ -1913,6 +1965,77 @@ sna_crtc_find_plane(struct sna *sna, int pipe)
#endif
}
static void
sna_crtc_init__rotation(struct sna *sna, struct sna_crtc *sna_crtc)
{
drmModeObjectPropertiesPtr props;
sna_crtc->supported_rotations = RR_Rotate_0;
sna_crtc->rotation = sna_crtc->last_rotation = RR_Rotate_0;
#if USE_ROTATION
props = drmModeObjectGetProperties(sna->kgem.fd,
sna_crtc->id,
DRM_MODE_OBJECT_CRTC);
if (props) {
int i, j;
DBG(("%s: CRTC:%d has %d props\n", __FUNCTION__, sna_crtc->id, props->count_props));
for (i = 0; i < props->count_props; i++) {
struct drm_mode_get_property prop;
struct drm_mode_property_enum *enums;
memset(&prop, 0, sizeof(prop));
prop.prop_id = props->props[i];
if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
continue;
DBG(("%s: prop[%d] .id=%d, .name=%s, .flags=%x, .value=%ld\n", __FUNCTION__, i,
props->props[i], prop.name, prop.flags, props->prop_values[i]));
if ((prop.flags & DRM_MODE_PROP_BITMASK) == 0)
continue;
if (strcmp(prop.name, "rotation"))
continue;
/* Note that this property only controls the primary
* plane, not the cursor or sprite planes.
*/
sna_crtc->rotation_id = props->props[i];
sna_crtc->rotation = sna_crtc->last_rotation = props->prop_values[i];
DBG(("%s: found rotation property .id=%d, num_enums=%d\n",
__FUNCTION__, prop.prop_id, prop.count_enum_blobs));
enums = malloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum));
if (enums != NULL) {
prop.count_values = 0;
prop.enum_blob_ptr = (uintptr_t)enums;
if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPERTY, &prop) == 0) {
/* XXX we assume that the mapping between kernel enum and
* RandR remains fixed for our lifetimes.
*/
for (j = 0; j < prop.count_enum_blobs; j++) {
DBG(("%s: CRTC:%d rotation[%d] = %s [%x]\n", __FUNCTION__, sna_crtc->id, j,
enums[j].name, enums[j].value));
sna_crtc->supported_rotations |= 1 << enums[j].value;
}
}
free(enums);
}
break;
}
drmModeFreeObjectProperties(props);
}
#endif
DBG(("%s: CRTC:%d [pipe=%d], supported-rotations=%x, current-rotation=%x\n",
__FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->supported_rotations, sna_crtc->last_rotation));
}
static bool
sna_crtc_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
{
@ -1921,7 +2044,7 @@ sna_crtc_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
struct sna_crtc *sna_crtc;
struct drm_i915_get_pipe_from_crtc_id get_pipe;
DBG(("%s\n", __FUNCTION__));
DBG(("%s(%d)\n", __FUNCTION__, num));
sna_crtc = calloc(sizeof(struct sna_crtc), 1);
if (sna_crtc == NULL)
@ -1963,6 +2086,8 @@ sna_crtc_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
DBG(("%s: created handle=%d for cursor on CRTC:%d\n",
__FUNCTION__, sna_crtc->cursor, sna_crtc->id));
sna_crtc_init__rotation(sna, sna_crtc);
crtc->driver_private = sna_crtc;
DBG(("%s: attached crtc[%d] id=%d, pipe=%d\n",
__FUNCTION__, num, sna_crtc->id, sna_crtc->pipe));