[PATCH xf86-video-ati 3/3] Make Option "TearFree" effective for rotated/reflected outputs as well

Alex Deucher alexdeucher at gmail.com
Tue Mar 8 16:54:44 UTC 2016


On Tue, Mar 8, 2016 at 4:48 AM, Michel Dänzer <michel at daenzer.net> wrote:
> From: Michel Dänzer <michel.daenzer at amd.com>
>
> 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 <michel.daenzer at amd.com>

For the series:
Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

> ---
>  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
> xorg-driver-ati at lists.x.org
> https://lists.x.org/mailman/listinfo/xorg-driver-ati


More information about the xorg-driver-ati mailing list