From 798c4fd16d339b1ad5fd729cc884be084c60e38b Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Fri, 25 Dec 2015 18:57:42 +0900 Subject: Make Option "TearFree" effective for rotated/reflected outputs as well (v2) Support varies by xserver version: < 1.12: No support for the driver handling rotation/reflection 1.12-1.15: Support for driver handling rotation/reflection, but there's a bug preventing the HW cursor from being visible everywhere it should be on rotated outputs, so we can only support TearFree for reflection. >= 1.16: While the bug above is still there (fixes pending review), the driver can force SW cursor for rotated outputs, so we can support TearFree for rotation as well. v2: Don't set crtc->driverIsPerformingTransform after xf86CrtcRotate if it wasn't set before. Fixes breaking rotation with TearFree disabled. Reviewed-by: Alex Deucher (v1) --- src/drmmode_display.c | 132 +++++++++++++++++++++++++++++++++++++++++++++----- src/radeon_kms.c | 123 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 214 insertions(+), 41 deletions(-) diff --git a/src/drmmode_display.c b/src/drmmode_display.c index cc71dd09..80fbbf6f 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -617,6 +617,34 @@ radeon_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) damage->damage.data = NULL; } +#if XF86_CRTC_VERSION >= 4 + +static Bool +drmmode_handle_transform(xf86CrtcPtr crtc) +{ + RADEONInfoPtr info = RADEONPTR(crtc->scrn); + Bool ret; + + crtc->driverIsPerformingTransform = info->tear_free && + !crtc->transformPresent && crtc->rotation != RR_Rotate_0; + + ret = xf86CrtcRotate(crtc); + + crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use; + + return ret; +} + +#else + +static Bool +drmmode_handle_transform(xf86CrtcPtr crtc) +{ + return xf86CrtcRotate(crtc); +} + +#endif + static Bool drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, int x, int y) @@ -694,9 +722,9 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, output_count++; } - if (!xf86CrtcRotate(crtc)) { + if (!drmmode_handle_transform(crtc)) goto done; - } + crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, crtc->gamma_blue, crtc->gamma_size); @@ -718,7 +746,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[0]); drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[1]); - } else if (info->tear_free || info->shadow_primary) { + } else if (info->tear_free || info->shadow_primary || + crtc->driverIsPerformingTransform) { for (i = 0; i < (info->tear_free ? 2 : 1); i++) { drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[i], @@ -744,8 +773,17 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, pBox = RegionExtents(pRegion); pBox->x1 = min(pBox->x1, x); pBox->y1 = min(pBox->y1, y); - pBox->x2 = max(pBox->x2, x + mode->HDisplay); - pBox->y2 = max(pBox->y2, y + mode->VDisplay); + + switch (crtc->rotation & 0xf) { + case RR_Rotate_90: + case RR_Rotate_270: + pBox->x2 = max(pBox->x2, x + mode->VDisplay); + pBox->y2 = max(pBox->y2, y + mode->HDisplay); + break; + default: + pBox->x2 = max(pBox->x2, x + mode->HDisplay); + pBox->y2 = max(pBox->y2, y + mode->VDisplay); + } } } @@ -821,24 +859,89 @@ drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; +#if XF86_CRTC_VERSION >= 4 + if (crtc->driverIsPerformingTransform) { + x += crtc->x; + y += crtc->y; + xf86CrtcTransformCursorPos(crtc, &x, &y); + } +#endif + drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); } +#if XF86_CRTC_VERSION >= 4 + +static int +drmmode_cursor_src_offset(Rotation rotation, int width, int height, + int x_dst, int y_dst) +{ + int t; + + switch (rotation & 0xf) { + case RR_Rotate_90: + t = x_dst; + x_dst = height - y_dst - 1; + y_dst = t; + break; + case RR_Rotate_180: + x_dst = width - x_dst - 1; + y_dst = height - y_dst - 1; + break; + case RR_Rotate_270: + t = x_dst; + x_dst = y_dst; + y_dst = width - t - 1; + break; + } + + if (rotation & RR_Reflect_X) + x_dst = width - x_dst - 1; + if (rotation & RR_Reflect_Y) + y_dst = height - y_dst - 1; + + return y_dst * height + x_dst; +} + +#endif + static void drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) { ScrnInfoPtr pScrn = crtc->scrn; RADEONInfoPtr info = RADEONPTR(pScrn); drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - int i; uint32_t *ptr; - uint32_t cursor_size = info->cursor_w * info->cursor_h; /* cursor should be mapped already */ ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr); - for (i = 0; i < cursor_size; i++) - ptr[i] = cpu_to_le32(image[i]); +#if XF86_CRTC_VERSION >= 4 + if (crtc->driverIsPerformingTransform) { + uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; + int dstx, dsty; + int srcoffset; + + for (dsty = 0; dsty < cursor_h; dsty++) { + for (dstx = 0; dstx < cursor_w; dstx++) { + srcoffset = drmmode_cursor_src_offset(crtc->rotation, + cursor_w, + cursor_h, + dstx, dsty); + + ptr[dsty * info->cursor_w + dstx] = + cpu_to_le32(image[srcoffset]); + } + } + } else +#endif + { + uint32_t cursor_size = info->cursor_w * info->cursor_h; + int i; + + for (i = 0; i < cursor_size; i++) + ptr[i] = cpu_to_le32(image[i]); + } } #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) @@ -849,6 +952,13 @@ static Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image) if (crtc->transformPresent) return FALSE; + /* Xorg doesn't correctly handle cursor position transform in the + * rotation case + */ + if (crtc->driverIsPerformingTransform && + (crtc->rotation & 0xf) != RR_Rotate_0) + return FALSE; + drmmode_load_cursor_argb(crtc, image); return TRUE; } @@ -2276,8 +2386,8 @@ Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, crtc->rotation = crtc->desiredRotation; crtc->x = crtc->desiredX; crtc->y = crtc->desiredY; - if (!xf86CrtcRotate(crtc)) - return FALSE; + if (!drmmode_handle_transform(crtc)) + return FALSE; } } return TRUE; diff --git a/src/radeon_kms.c b/src/radeon_kms.c index 44fe71e1..8048c95f 100644 --- a/src/radeon_kms.c +++ b/src/radeon_kms.c @@ -334,12 +334,22 @@ radeon_dirty_update(ScreenPtr screen) #endif static Bool -radeon_scanout_extents_intersect(BoxPtr extents, int x, int y, int w, int h) +radeon_scanout_extents_intersect(xf86CrtcPtr xf86_crtc, BoxPtr extents, int w, + int h) { - extents->x1 = max(extents->x1 - x, 0); - extents->y1 = max(extents->y1 - y, 0); - extents->x2 = min(extents->x2 - x, w); - extents->y2 = min(extents->y2 - y, h); + extents->x1 = max(extents->x1 - xf86_crtc->x, 0); + extents->y1 = max(extents->y1 - xf86_crtc->y, 0); + + switch (xf86_crtc->rotation & 0xf) { + case RR_Rotate_90: + case RR_Rotate_270: + extents->x2 = min(extents->x2 - xf86_crtc->x, h); + extents->y2 = min(extents->y2 - xf86_crtc->y, w); + break; + default: + extents->x2 = min(extents->x2 - xf86_crtc->x, w); + extents->y2 = min(extents->y2 - xf86_crtc->y, h); + } return (extents->x1 < extents->x2 && extents->y1 < extents->y2); } @@ -353,7 +363,6 @@ radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id) RegionPtr pRegion; DrawablePtr pDraw; ScreenPtr pScreen; - GCPtr gc; BoxRec extents; RADEONInfoPtr info; Bool force; @@ -372,31 +381,87 @@ radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id) return FALSE; pDraw = &drmmode_crtc->scanout[scanout_id].pixmap->drawable; + pScreen = pDraw->pScreen; extents = *RegionExtents(pRegion); RegionEmpty(pRegion); - if (!radeon_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y, - pDraw->width, pDraw->height)) + if (!radeon_scanout_extents_intersect(xf86_crtc, &extents, pDraw->width, + pDraw->height)) return FALSE; - pScreen = pDraw->pScreen; - gc = GetScratchGC(pDraw->depth, pScreen); scrn = xf86_crtc->scrn; info = RADEONPTR(scrn); force = info->accel_state->force; info->accel_state->force = TRUE; - ValidateGC(pDraw, gc); - (*gc->ops->CopyArea)(&pScreen->GetScreenPixmap(pScreen)->drawable, - pDraw, gc, - xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1, - extents.x2 - extents.x1, extents.y2 - extents.y1, - extents.x1, extents.y1); - FreeScratchGC(gc); + if (xf86_crtc->driverIsPerformingTransform) { + SourceValidateProcPtr SourceValidate = pScreen->SourceValidate; + PictFormatPtr format = PictureWindowFormat(pScreen->root); + int error; + PicturePtr src, dst; + XID include_inferiors = IncludeInferiors; + + src = CreatePicture(None, + &pScreen->root->drawable, + format, + CPSubwindowMode, + &include_inferiors, serverClient, &error); + if (!src) { + ErrorF("Failed to create source picture for transformed scanout " + "update\n"); + goto out; + } + + dst = CreatePicture(None, pDraw, format, 0L, NULL, serverClient, &error); + if (!dst) { + ErrorF("Failed to create destination picture for transformed scanout " + "update\n"); + goto out; + } - info->accel_state->force = force; + error = SetPictureTransform(src, &xf86_crtc->crtc_to_framebuffer); + if (error) { + ErrorF("SetPictureTransform failed for transformed scanout " + "update\n"); + goto out; + } + + if (xf86_crtc->filter) + SetPicturePictFilter(src, xf86_crtc->filter, xf86_crtc->params, + xf86_crtc->nparams); + + extents.x1 += xf86_crtc->x - (xf86_crtc->filter_width >> 1); + extents.x2 += xf86_crtc->x + (xf86_crtc->filter_width >> 1); + extents.y1 += xf86_crtc->y - (xf86_crtc->filter_height >> 1); + extents.y2 += xf86_crtc->y + (xf86_crtc->filter_height >> 1); + pixman_f_transform_bounds(&xf86_crtc->f_framebuffer_to_crtc, &extents); + + pScreen->SourceValidate = NULL; + CompositePicture(PictOpSrc, + src, NULL, dst, + extents.x1, extents.y1, 0, 0, extents.x1, + extents.y1, extents.x2 - extents.x1, + extents.y2 - extents.y1); + pScreen->SourceValidate = SourceValidate; + + FreePicture(src, None); + FreePicture(dst, None); + } else { + GCPtr gc = GetScratchGC(pDraw->depth, pScreen); + + ValidateGC(pDraw, gc); + (*gc->ops->CopyArea)(&pScreen->GetScreenPixmap(pScreen)->drawable, + pDraw, gc, + xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1, + extents.x2 - extents.x1, extents.y2 - extents.y1, + extents.x1, extents.y1); + FreeScratchGC(gc); + } radeon_cs_flush_indirect(scrn); + out: + info->accel_state->force = force; + return TRUE; } @@ -445,8 +510,8 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc) pDraw = &drmmode_crtc->scanout[0].pixmap->drawable; extents = *RegionExtents(pRegion); - if (!radeon_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y, - pDraw->width, pDraw->height)) + if (!radeon_scanout_extents_intersect(xf86_crtc, &extents, pDraw->width, + pDraw->height)) return; scrn = xf86_crtc->scrn; @@ -532,21 +597,19 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL) SCREEN_PTR(arg); ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); RADEONInfoPtr info = RADEONPTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; pScreen->BlockHandler = info->BlockHandler; (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS); pScreen->BlockHandler = RADEONBlockHandler_KMS; - if (info->tear_free || info->shadow_primary) { - xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - int c; - - for (c = 0; c < xf86_config->num_crtc; c++) { - if (info->tear_free) - radeon_scanout_flip(pScreen, info, xf86_config->crtc[c]); - else - radeon_scanout_update(xf86_config->crtc[c]); - } + for (c = 0; c < xf86_config->num_crtc; c++) { + if (info->tear_free) + radeon_scanout_flip(pScreen, info, xf86_config->crtc[c]); + else if (info->shadow_primary || + xf86_config->crtc[c]->driverIsPerformingTransform) + radeon_scanout_update(xf86_config->crtc[c]); } radeon_cs_flush_indirect(pScrn); -- cgit v1.2.3