From patchwork Wed Jul 9 11:14:41 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Wilson X-Patchwork-Id: 4513391 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 815799F3FF for ; Wed, 9 Jul 2014 11:15:05 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id F35EE20379 for ; Wed, 9 Jul 2014 11:15:03 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id E05DA20357 for ; Wed, 9 Jul 2014 11:15:00 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id DBBE06E2D0; Wed, 9 Jul 2014 04:14:59 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from fireflyinternet.com (mail.fireflyinternet.com [87.106.93.118]) by gabe.freedesktop.org (Postfix) with ESMTP id EEA526E670 for ; Wed, 9 Jul 2014 04:14:57 -0700 (PDT) X-Default-Received-SPF: pass (skip=forwardok (res=PASS)) x-ip-name=78.156.65.138; Received: from cantiga.alporthouse.com (unverified [78.156.65.138]) by fireflyinternet.com (Firefly Internet (M1)) with ESMTP id 27418784-1500048 for multiple; Wed, 09 Jul 2014 12:15:05 +0100 Received: by cantiga.alporthouse.com (sSMTP sendmail emulation); Wed, 09 Jul 2014 12:14:42 +0100 From: Chris Wilson To: dri-devel@lists.freedesktop.org, xorg-devel@lists.x.org Subject: [PATCH] modesetting: Support native primary plane rotation Date: Wed, 9 Jul 2014 12:14:41 +0100 Message-Id: <1404904481-22955-1-git-send-email-chris@chris-wilson.co.uk> X-Mailer: git-send-email 2.0.1 In-Reply-To: <1404893948-18819-1-git-send-email-chris@chris-wilson.co.uk> References: <1404893948-18819-1-git-send-email-chris@chris-wilson.co.uk> X-Originating-IP: 78.156.65.138 X-Country: code=GB country="United Kingdom" ip=78.156.65.138 Cc: Pekka Paalanen , walter harms X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP With the advent of universal drm planes and the introduction of generic plane properties for rotations, we can query and program the hardware for native rotation support. NOTE: this depends upon the next release of libdrm to remove one opencoded define. v2: Use enum to determine primary plane, suggested by Pekka Paalanen. Use libobj for replacement ffs(), suggested by walter harms v3: Support combinations of rotations and reflections Eliminate use of ffs() and so remove need for libobj Signed-off-by: Chris Wilson Cc: Pekka Paalanen Cc: walter harms --- configure.ac | 2 +- src/drmmode_display.c | 258 ++++++++++++++++++++++++++++++++++++++++++++------ src/drmmode_display.h | 10 +- 3 files changed, 237 insertions(+), 33 deletions(-) diff --git a/configure.ac b/configure.ac index 1c1a36d..783c243 100644 --- a/configure.ac +++ b/configure.ac @@ -74,7 +74,7 @@ AM_CONDITIONAL(HAVE_XEXTPROTO_71, [ test "$HAVE_XEXTPROTO_71" = "yes" ]) # Checks for header files. AC_HEADER_STDC -PKG_CHECK_MODULES(DRM, [libdrm >= 2.4.46]) +PKG_CHECK_MODULES(DRM, [libdrm >= 2.4.47]) PKG_CHECK_MODULES([PCIACCESS], [pciaccess >= 0.10]) AM_CONDITIONAL(DRM, test "x$DRM" = xyes) diff --git a/src/drmmode_display.c b/src/drmmode_display.c index c533324..93c48ac 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -56,6 +56,8 @@ #include "driver.h" +#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2 /* from libdrm 2.4.55 */ + static struct dumb_bo *dumb_bo_create(int fd, const unsigned width, const unsigned height, const unsigned bpp) @@ -300,6 +302,171 @@ create_pixmap_for_fbcon(drmmode_ptr drmmode, #endif +static void +rotation_init(xf86CrtcPtr crtc) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + drmModePlaneRes *plane_resources; + int i, j, k; + + drmSetClientCap(drmmode->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + + plane_resources = drmModeGetPlaneResources(drmmode->fd); + if (plane_resources == NULL) + return; + + for (i = 0; drmmode_crtc->primary_plane_id == 0 && i < plane_resources->count_planes; i++) { + drmModePlane *drm_plane; + drmModeObjectPropertiesPtr proplist; + int is_primary = -1; + + drm_plane = drmModeGetPlane(drmmode->fd, + plane_resources->planes[i]); + if (drm_plane == NULL) + continue; + + if (!(drm_plane->possible_crtcs & (1 << drmmode_crtc->index))) + goto free_plane; + + proplist = drmModeObjectGetProperties(drmmode->fd, + drm_plane->plane_id, + DRM_MODE_OBJECT_PLANE); + if (proplist == NULL) + goto free_plane; + + for (j = 0; is_primary == -1 && j < proplist->count_props; j++) { + drmModePropertyPtr prop; + + prop = drmModeGetProperty(drmmode->fd, proplist->props[j]); + if (!prop) + continue; + + if (strcmp(prop->name, "type") == 0) { + for (k = 0; k < prop->count_enums; k++) { + if (prop->enums[k].value != proplist->prop_values[j]) + continue; + + is_primary = strcmp(prop->enums[k].name, "Primary") == 0; + break; + } + } + + drmModeFreeProperty(prop); + } + + if (is_primary) { + drmmode_crtc->primary_plane_id = drm_plane->plane_id; + + for (j = 0; drmmode_crtc->rotation_prop_id == 0 && j < proplist->count_props; j++) { + drmModePropertyPtr prop; + + prop = drmModeGetProperty(drmmode->fd, proplist->props[j]); + if (!prop) + continue; + + if (strcmp(prop->name, "rotation") == 0) { + drmmode_crtc->rotation_prop_id = proplist->props[j]; + drmmode_crtc->current_rotation = proplist->prop_values[j]; + for (k = 0; k < prop->count_enums; k++) { + int rr = -1; + if (strcmp(prop->enums[k].name, "rotate-0") == 0) + rr = 0; /* RR_Rotate_0 */ + else if (strcmp(prop->enums[k].name, "rotate-90") == 0) + rr = 1; /* RR_Rotate_90 */ + else if (strcmp(prop->enums[k].name, "rotate-180") == 0) + rr = 2; /* RR_Rotate_180 */ + else if (strcmp(prop->enums[k].name, "rotate-270") == 0) + rr = 3; /* RR_Rotate_270 */ + else if (strcmp(prop->enums[k].name, "reflect-x") == 0) + rr = 4; /* RR_Reflect_X */ + else if (strcmp(prop->enums[k].name, "reflect-y") == 0) + rr = 5; /* RR_Reflect_Y */ + if (rr != -1) { + drmmode_crtc->map_rotations[rr] = prop->enums[k].value; + drmmode_crtc->supported_rotations |= 1 << rr; + } + } + } + + drmModeFreeProperty(prop); + } + } + + drmModeFreeObjectProperties(proplist); +free_plane: + drmModeFreePlane(drm_plane); + } +} + +static unsigned int +rotation_to_kernel(xf86CrtcPtr crtc, unsigned rotation) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + unsigned mapped = 0; + int i; + + for (i = 0; rotation; i++) { + if (rotation & (1 << i)) { + mapped |= 1 << drmmode_crtc->map_rotations[i]; + rotation &= ~(1 << i); + } + } + + return mapped; +} + +static Bool +rotation_set(xf86CrtcPtr crtc, unsigned rotation) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + + if (drmmode_crtc->current_rotation == rotation) + return TRUE; + + if ((drmmode_crtc->supported_rotations & rotation) != rotation) + return FALSE; + + if (drmModeObjectSetProperty(drmmode->fd, + drmmode_crtc->primary_plane_id, + DRM_MODE_OBJECT_PLANE, + drmmode_crtc->rotation_prop_id, + rotation_to_kernel(crtc, rotation))) + return FALSE; + + drmmode_crtc->current_rotation = rotation; + return TRUE; +} + +static unsigned +rotation_reduce(xf86CrtcPtr crtc, unsigned rotation) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + unsigned unsupported_rotations = rotation & ~drmmode_crtc->supported_rotations; + + if (unsupported_rotations == 0) + return rotation; + +#define RR_Reflect_XY (RR_Reflect_X | RR_Reflect_Y) + + if ((unsupported_rotations & RR_Reflect_XY) == RR_Reflect_XY && + drmmode_crtc->supported_rotations & RR_Rotate_180) { + rotation &= ~RR_Reflect_XY; + rotation ^= RR_Rotate_180; + } + + if ((unsupported_rotations & RR_Rotate_180) && + (drmmode_crtc->supported_rotations & RR_Reflect_XY) == RR_Reflect_XY) { + rotation ^= RR_Reflect_XY; + rotation &= ~RR_Rotate_180; + } + +#undef RR_Reflect_XY + + return rotation; +} + static Bool drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, int x, int y) @@ -307,13 +474,14 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, ScrnInfoPtr pScrn = crtc->scrn; xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + unsigned supported_rotations = drmmode_crtc->supported_rotations; drmmode_ptr drmmode = drmmode_crtc->drmmode; int saved_x, saved_y; Rotation saved_rotation; DisplayModeRec saved_mode; uint32_t *output_ids; int output_count = 0; - Bool ret = TRUE; + int ret; int i; uint32_t fb_id; drmModeModeInfo kmode; @@ -324,15 +492,16 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, if (drmmode->fb_id == 0) { ret = drmModeAddFB(drmmode->fd, pScrn->virtualX, height, - pScrn->depth, pScrn->bitsPerPixel, + pScrn->depth, pScrn->bitsPerPixel, drmmode->front_bo->pitch, drmmode->front_bo->handle, - &drmmode->fb_id); - if (ret < 0) { - ErrorF("failed to add fb %d\n", ret); - return FALSE; - } - } + &drmmode->fb_id); + if (ret) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "failed to create framebuffer: %s\n", strerror(-ret)); + return FALSE; + } + } saved_mode = crtc->mode; saved_x = crtc->x; @@ -349,11 +518,11 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, #endif } + rotation = rotation_reduce(crtc, rotation); + output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); - if (!output_ids) { - ret = FALSE; - goto done; - } + if (!output_ids) + goto err; if (mode) { for (i = 0; i < xf86_config->num_output; i++) { @@ -368,9 +537,17 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, output_count++; } - if (!xf86CrtcRotate(crtc)) { - goto done; - } + rotation_set(crtc, RR_Rotate_0); + +again: + crtc->driverIsPerformingTransform = FALSE; + if (!crtc->transformPresent && + (rotation & supported_rotations) == rotation) + crtc->driverIsPerformingTransform = TRUE; + + if (!xf86CrtcRotate(crtc)) + goto err; + #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0) crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, crtc->gamma_blue, crtc->gamma_size); @@ -392,11 +569,20 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, } ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, fb_id, x, y, output_ids, output_count, &kmode); - if (ret) + if (ret) { xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, - "failed to set mode: %s", strerror(-ret)); - else - ret = TRUE; + "failed to set mode: %s\n", strerror(-ret)); + goto err; + } + + if (crtc->driverIsPerformingTransform) { + if (!rotation_set(crtc, rotation)) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "failed to set rotation: %s\n", strerror(errno)); + supported_rotations &= ~rotation; + goto again; + } + } if (crtc->scrn->pScreen) xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen); @@ -409,26 +595,33 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, output->funcs->dpms(output, DPMSModeOn); } + } else { + ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + 0, 0, 0, NULL, 0, NULL) == 0; + if (ret) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "failed to set mode: %s\n", strerror(-ret)); + goto err; + } } +#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3 + crtc->active = mode != NULL; +#endif + #if 0 if (pScrn->pScreen && !xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) xf86_reload_cursors(pScrn->pScreen); #endif -done: - if (!ret) { - crtc->x = saved_x; - crtc->y = saved_y; - crtc->rotation = saved_rotation; - crtc->mode = saved_mode; - } -#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3 - else - crtc->active = TRUE; -#endif + return TRUE; - return ret; +err: + crtc->x = saved_x; + crtc->y = saved_y; + crtc->rotation = saved_rotation; + crtc->mode = saved_mode; + return FALSE; } static void @@ -610,7 +803,10 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]); drmmode_crtc->drmmode = drmmode; + drmmode_crtc->index = num; crtc->driver_private = drmmode_crtc; + + rotation_init(crtc); } static xf86OutputStatus diff --git a/src/drmmode_display.h b/src/drmmode_display.h index 745c484..73fabfd 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -75,8 +75,13 @@ typedef struct { typedef struct { drmmode_ptr drmmode; drmModeCrtcPtr mode_crtc; - int hw_id; + int index; struct dumb_bo *cursor_bo; + unsigned primary_plane_id; + unsigned rotation_prop_id; + unsigned supported_rotations; + unsigned map_rotations[6]; + unsigned current_rotation; unsigned rotate_fb_id; uint16_t lut_r[256], lut_g[256], lut_b[256]; DamagePtr slave_damage; @@ -145,5 +150,8 @@ void drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmmode, int *depth #define MS_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +#ifndef HAVE_FFS +extern int ffs(unsigned int value); +#endif #endif