vblank problem (and proposed fix) on crtc > 1

Michel Dänzer michel at daenzer.net
Thu Mar 10 04:31:44 PST 2011


On Mit, 2011-03-09 at 11:33 -0600, Ilija Hadzic wrote: 
> 
> So what I did is to actually probe the kernel at screen init time. 
> When the screen is initialized, the DDX checks if the GPU has more than
> two CRTCs and tries a dummy vblank wait on all crtcs > 1. If any
> of them fails, it falls back to the old method of using only
> primary/secondary flag. 

I'm afraid I don't really like this. Apart from the ugly bogus error
message, the probes could fail for other reasons, e.g. at some point we
might want to return an error when the ioctl is called for a CRTC which
is currently disabled, to avoid the hang you were getting for CRTC 1.


Dave's drm-next tree actually has a new DRM_IOCTL_GET_CAP ioctl, which
could be used for detecting this capability. It might even be possible
to handle old kernels transparently in drmWaitVBlank(), but I'm not sure
offhand if that would be better overall than doing it in the driver
code.


Some detailed technical comments:

> diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
> index 66df03c..c45abe6 100644
> --- a/src/radeon_dri2.c
> +++ b/src/radeon_dri2.c
> @@ -1145,8 +1193,15 @@ 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;

Waiting on a random other CRTC makes no sense. If you know you can't
wait on the given CRTC, don't wait at all. 


> @@ -1261,6 +1319,22 @@ 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) {
> +       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "GPU with %d CRTCs found, probing VBLANKs on CRTC>1\n",
> +                  info->drmmode.mode_res->count_crtcs); 
> +       info->high_crtc_works = TRUE;
> +       for (c=2; c<info->drmmode.mode_res->count_crtcs; c++) {
> +           vbl.request.type = DRM_VBLANK_RELATIVE;
> +           vbl.request.type |= (c << DRM_VBLANK_HIGH_CRTC_SHIFT) & DRM_VBLANK_HIGH_CRTC_MASK;
> +           vbl.request.sequence = 0;
> +           if (drmWaitVBlank(info->dri2.drm_fd, &vbl)) {
> +               xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Kernel rejects VBLANK request on CRTC %d\n", c);
> +               info->high_crtc_works = FALSE;

Should break out of the for loop at this point. 

> +           }
> +       }
> +       if (info->high_crtc_works) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBLANK request accepted on all CRTCs\n"); 

The statement guarded by the if condition needs to go on a new line, and
please don't add trailing whitespace. Also, again, please match the
indentation of the surrounding code.


-- 
Earthling Michel Dänzer           |                http://www.vmware.com
Libre software enthusiast         |          Debian, X and DRI developer


More information about the dri-devel mailing list