On Sat, 19 Mar 2011, Alex Deucher wrote:
> 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> > Signed-off-by: Ilija Hadzic <ihadzic at research.bell-labs.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))) { >> >