@@ -930,6 +930,9 @@ typedef struct {
RADEONFBLayout CurrentLayout;
+#ifdef RADEON_DRI2
+ Bool high_crtc_works;
+#endif
#ifdef XF86DRI
Bool directRenderingEnabled;
Bool directRenderingInited;
@@ -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,15 @@ 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 +1062,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 +1102,15 @@ 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 +1152,15 @@ 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 +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;
+ }
+ vbl.request.type |= high_crtc;
vbl.request.sequence = current_msc - (current_msc % divisor) +
remainder;
@@ -1217,6 +1272,8 @@ radeon_dri2_screen_init(ScreenPtr pScreen)
DRI2InfoRec dri2_info = { 0 };
#ifdef USE_DRI2_SCHEDULING
const char *driverNames[1];
+ drmVBlank vbl;
+ int c;
#endif
if (!info->useEXA) {
@@ -1248,6 +1305,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 +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;
+ }
+ }
+ if (info->high_crtc_works) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBLANK request accepted on all CRTCs\n");
+ }
+
if (pRADEONEnt->dri2_info_cnt == 0) {
#if HAS_DIXREGISTERPRIVATEKEY
if (!dixRegisterPrivateKey(DRI2ClientEventsPrivateKey, PRIVATE_CLIENT, sizeof(DRI2ClientEventsRec))) {