[PATCH] xf86-video-ati: vblank wait on crtc > 1

Alex Deucher alexdeucher at gmail.com
Sat Mar 19 12:37:08 PDT 2011


On Fri, Mar 18, 2011 at 5:58 PM, Ilija Hadzic
<ihadzic at research.bell-labs.com> wrote:
>
> Hi Alex,
>
> Below is a patch against the master branch of xf86-video-ati that adds
> support for waits on vblank events on CRTCs that are greater than 1 (and
> thus cannot be represented using current primary/secondary flags interface).
> The patch makes use of GET_CAP ioctl to check whether
> vblanks on crtc > 1 are supported by the kernel. If they are not
> falls back to legacy behavior. Otherwise, it uses correct crtc numbers
> when waiting on vblank and thus corrects the problem seen in certain
> multiscreen configurations.
>
> The issue was discussed on the dri-devel list in these two threads
>
> http://lists.freedesktop.org/archives/dri-devel/2011-March/009009.html
> http://lists.freedesktop.org/archives/dri-devel/2011-March/009025.html
>
> regards,
>
> Ilija
>
> Reviewed-by: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>
> Acked-by: Mario Kleiner <mario.kleiner at tuebingen.mpg.de>


Reviewed-by: Alex Deucher <alexdeucher at gmail.com>
Tested-by: Alex Deucher <alexdeucher at gmail.com>

>
> diff --git a/src/radeon.h b/src/radeon.h
> index a6d20d7..1a746c7 100644
> --- a/src/radeon.h
> +++ b/src/radeon.h
> @@ -931,6 +931,9 @@ typedef struct {
>
>     RADEONFBLayout    CurrentLayout;
>
> +#ifdef RADEON_DRI2
> +    Bool              high_crtc_works;
> +#endif
>  #ifdef XF86DRI
>     Bool              directRenderingEnabled;
>     Bool              directRenderingInited;
> diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
> index 66df03c..ed27dad 100644
> --- a/src/radeon_dri2.c
> +++ b/src/radeon_dri2.c
> @@ -783,6 +783,7 @@ static int radeon_dri2_get_msc(DrawablePtr draw, CARD64
> *ust, CARD64 *msc)
>     drmVBlank vbl;
>     int ret;
>     int crtc = radeon_dri2_drawable_crtc(draw);
> +    int high_crtc = 0;
>
>     /* Drawable not displayed, make up a value */
>     if (crtc == -1) {
> @@ -791,8 +792,16 @@ static int radeon_dri2_get_msc(DrawablePtr draw, CARD64
> *ust, CARD64 *msc)
>         return TRUE;
>     }
>     vbl.request.type = DRM_VBLANK_RELATIVE;
> -    if (crtc > 0)
> +    if (crtc == 1)
>         vbl.request.type |= DRM_VBLANK_SECONDARY;
> +    else if (crtc > 1) {
> +       if (info->high_crtc_works) {
> +           high_crtc = (crtc << DRM_VBLANK_HIGH_CRTC_SHIFT) &
> +               DRM_VBLANK_HIGH_CRTC_MASK;
> +       } else
> +           vbl.request.type |= DRM_VBLANK_SECONDARY;
> +    }
> +    vbl.request.type |= high_crtc;
>     vbl.request.sequence = 0;
>
>     ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
> @@ -825,6 +834,7 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr
> client, DrawablePtr draw,
>     drmVBlank vbl;
>     int ret, crtc = radeon_dri2_drawable_crtc(draw);
>     CARD64 current_msc;
> +    int high_crtc = 0;
>
>     /* Truncate to match kernel interfaces; means occasional overflow
>      * misses, but that's generally not a big deal */
> @@ -855,8 +865,16 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr
> client, DrawablePtr draw,
>
>     /* Get current count */
>     vbl.request.type = DRM_VBLANK_RELATIVE;
> -    if (crtc > 0)
> +    if (crtc == 1)
>         vbl.request.type |= DRM_VBLANK_SECONDARY;
> +    else if (crtc > 1) {
> +       if (info->high_crtc_works) {
> +           high_crtc = (crtc << DRM_VBLANK_HIGH_CRTC_SHIFT) &
> +               DRM_VBLANK_HIGH_CRTC_MASK;
> +       } else
> +           vbl.request.type |= DRM_VBLANK_SECONDARY;
> +    }
> +    vbl.request.type |= high_crtc;
>     vbl.request.sequence = 0;
>     ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
>     if (ret) {
> @@ -882,8 +900,16 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr
> client, DrawablePtr draw,
>         if (current_msc >= target_msc)
>             target_msc = current_msc;
>         vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
> -        if (crtc > 0)
> +        if (crtc == 1)
>             vbl.request.type |= DRM_VBLANK_SECONDARY;
> +       else if (crtc > 1) {
> +           if (info->high_crtc_works) {
> +               high_crtc = (crtc << DRM_VBLANK_HIGH_CRTC_SHIFT) &
> +                   DRM_VBLANK_HIGH_CRTC_MASK;
> +           } else
> +               vbl.request.type |= DRM_VBLANK_SECONDARY;
> +       }
> +       vbl.request.type |= high_crtc;
>         vbl.request.sequence = target_msc;
>         vbl.request.signal = (unsigned long)wait_info;
>         ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
> @@ -903,8 +929,16 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr
> client, DrawablePtr draw,
>      * so we queue an event that will satisfy the divisor/remainder
> equation.
>      */
>     vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
> -    if (crtc > 0)
> +    if (crtc == 1)
>         vbl.request.type |= DRM_VBLANK_SECONDARY;
> +    else if (crtc > 1) {
> +       if (info->high_crtc_works) {
> +           high_crtc = (crtc << DRM_VBLANK_HIGH_CRTC_SHIFT) &
> +               DRM_VBLANK_HIGH_CRTC_MASK;
> +       } else
> +           vbl.request.type |= DRM_VBLANK_SECONDARY;
> +    }
> +    vbl.request.type |= high_crtc;
>
>     vbl.request.sequence = current_msc - (current_msc % divisor) +
>         remainder;
> @@ -1029,6 +1063,7 @@ static int radeon_dri2_schedule_swap(ClientPtr client,
> DrawablePtr draw,
>     CARD64 current_msc;
>     BoxRec box;
>     RegionRec region;
> +    int high_crtc = 0;
>
>     /* Truncate to match kernel interfaces; means occasional overflow
>      * misses, but that's generally not a big deal */
> @@ -1068,8 +1103,16 @@ static int radeon_dri2_schedule_swap(ClientPtr
> client, DrawablePtr draw,
>
>     /* Get current count */
>     vbl.request.type = DRM_VBLANK_RELATIVE;
> -    if (crtc > 0)
> +    if (crtc == 1)
>         vbl.request.type |= DRM_VBLANK_SECONDARY;
> +    else if (crtc > 1) {
> +       if (info->high_crtc_works) {
> +           high_crtc = (crtc << DRM_VBLANK_HIGH_CRTC_SHIFT) &
> +               DRM_VBLANK_HIGH_CRTC_MASK;
> +       } else
> +           vbl.request.type |= DRM_VBLANK_SECONDARY;
> +    }
> +    vbl.request.type |= high_crtc;
>     vbl.request.sequence = 0;
>     ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
>     if (ret) {
> @@ -1111,8 +1154,16 @@ static int radeon_dri2_schedule_swap(ClientPtr
> client, DrawablePtr draw,
>          */
>         if (flip == 0)
>             vbl.request.type |= DRM_VBLANK_NEXTONMISS;
> -        if (crtc > 0)
> +        if (crtc == 1)
>             vbl.request.type |= DRM_VBLANK_SECONDARY;
> +       else if (crtc > 1) {
> +           if (info->high_crtc_works) {
> +               high_crtc = (crtc << DRM_VBLANK_HIGH_CRTC_SHIFT) &
> +                   DRM_VBLANK_HIGH_CRTC_MASK;
> +           } else
> +               vbl.request.type |= DRM_VBLANK_SECONDARY;
> +       }
> +       vbl.request.type |= high_crtc;
>
>         /* If target_msc already reached or passed, set it to
>          * current_msc to ensure we return a reasonable value back
> @@ -1145,8 +1196,16 @@ static int radeon_dri2_schedule_swap(ClientPtr
> client, DrawablePtr draw,
>     vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
>     if (flip == 0)
>         vbl.request.type |= DRM_VBLANK_NEXTONMISS;
> -    if (crtc > 0)
> +    if (crtc == 1)
>         vbl.request.type |= DRM_VBLANK_SECONDARY;
> +    else if (crtc > 1) {
> +       if (info->high_crtc_works) {
> +           high_crtc = (crtc << DRM_VBLANK_HIGH_CRTC_SHIFT) &
> +               DRM_VBLANK_HIGH_CRTC_MASK;
> +       } else
> +           vbl.request.type |= DRM_VBLANK_SECONDARY;
> +    }
> +    vbl.request.type |= high_crtc;
>
>     vbl.request.sequence = current_msc - (current_msc % divisor) +
>         remainder;
> @@ -1217,6 +1276,7 @@ radeon_dri2_screen_init(ScreenPtr pScreen)
>     DRI2InfoRec dri2_info = { 0 };
>  #ifdef USE_DRI2_SCHEDULING
>     const char *driverNames[1];
> +    uint64_t cap_value;
>  #endif
>
>     if (!info->useEXA) {
> @@ -1248,6 +1308,7 @@ radeon_dri2_screen_init(ScreenPtr pScreen)
>  #endif
>     dri2_info.CopyRegion = radeon_dri2_copy_region;
>
> +    info->high_crtc_works = FALSE;
>  #ifdef USE_DRI2_SCHEDULING
>     if (info->dri->pKernelDRMVersion->version_minor >= 4) {
>         dri2_info.version = 4;
> @@ -1261,6 +1322,20 @@ radeon_dri2_screen_init(ScreenPtr pScreen)
>         xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for
> sync extension\n");
>     }
>
> +    if (info->drmmode.mode_res->count_crtcs > 2) {
> +       if (drmGetCap(info->dri2.drm_fd, DRM_CAP_HIGH_CRTC, &cap_value)) {
> +           info->high_crtc_works = FALSE;
> +           xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel
> for VBLANKs on CRTC>1\n");
> +       } else {
> +           if (cap_value) {
> +               info->high_crtc_works = TRUE;
> +           } else {
> +               xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Your kernel does
> not handle VBLANKs on CRTC>1\n");
> +               info->high_crtc_works = FALSE;
> +           }
> +       }
> +    }
> +
>     if (pRADEONEnt->dri2_info_cnt == 0) {
>  #if HAS_DIXREGISTERPRIVATEKEY
>        if (!dixRegisterPrivateKey(DRI2ClientEventsPrivateKey,
> PRIVATE_CLIENT, sizeof(DRI2ClientEventsRec))) {
>


More information about the dri-devel mailing list