On Tue, Mar 8, 2016 at 4:48 AM, Michel Dänzer <[email protected]> wrote: > From: Michel Dänzer <[email protected]> > > 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. > > Signed-off-by: Michel Dänzer <[email protected]>
For the series: Reviewed-by: Alex Deucher <[email protected]> > --- > 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 cc71dd0..c5a7eef 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 44fe71e..8048c95 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); > -- > 2.7.0 > > _______________________________________________ > xorg-driver-ati mailing list > [email protected] > https://lists.x.org/mailman/listinfo/xorg-driver-ati _______________________________________________ xorg-driver-ati mailing list [email protected] https://lists.x.org/mailman/listinfo/xorg-driver-ati
