From patchwork Fri Jul 11 06:41:47 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Wilson X-Patchwork-Id: 4530911 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 3B8C09F36A for ; Fri, 11 Jul 2014 06:42:21 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id F3CED201D5 for ; Fri, 11 Jul 2014 06:42:19 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 39EFC201D3 for ; Fri, 11 Jul 2014 06:42:18 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id ADC346E7FA; Thu, 10 Jul 2014 23:42:16 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from relay.fireflyinternet.com (hostedrelay.fireflyinternet.com [109.228.30.76]) by gabe.freedesktop.org (Postfix) with ESMTP id 9DD116E7FA for ; Thu, 10 Jul 2014 23:42:15 -0700 (PDT) X-Default-Received-SPF: pass (skip=forwardok (res=PASS)) x-ip-name=78.156.65.138; Received: from haswell.alporthouse.com (unverified [78.156.65.138]) by relay.fireflyinternet.com (FireflyRelay1) with ESMTP id 11473117-1305619 for multiple; Fri, 11 Jul 2014 07:42:30 +0100 From: Chris Wilson To: xorg-devel@lists.x.org, dri-devel@lists.freedesktop.org Subject: [PATCH] modesetting: Support native primary plane rotation Date: Fri, 11 Jul 2014 07:41:47 +0100 Message-Id: <1405060907-18674-1-git-send-email-chris@chris-wilson.co.uk> X-Mailer: git-send-email 2.0.1 In-Reply-To: <1404904481-22955-1-git-send-email-chris@chris-wilson.co.uk> References: <1404904481-22955-1-git-send-email-chris@chris-wilson.co.uk> X-Authenticated-User: chris.alporthouse@surfanytime.net Cc: Pekka Paalanen , walter harms , Mark Kettenis 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.8 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD,UNPARSEABLE_RELAY autolearn=ham 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 v4: And remove the vestigal HAVE_FFS, spotted by Mark Kettenis Signed-off-by: Chris Wilson Cc: Pekka Paalanen Cc: walter harms Cc: Mark Kettenis --- configure.ac | 2 +- src/drmmode_display.c | 258 ++++++++++++++++++++++++++++++++++++++++++++------ src/drmmode_display.h | 7 +- 3 files changed, 234 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..8eb25fd 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;