sna: Busy-wait for the kernel to catch up when flipping
authorChris Wilson <chris@chris-wilson.co.uk>
Thu, 17 Jul 2014 08:20:35 +0000 (09:20 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Thu, 17 Jul 2014 08:30:32 +0000 (09:30 +0100)
If the kernel reports that it is busy, it has not yet finished
processing a pending flip and we have multiple CRTC queued, just wait
for the kernel to clear its backlog before submitting the next flip. On
the other hand, if we can just overwrite the pending flip results.
However, the EBUSY may actually be a genuine report by the kernel of an
error, so check for an invalid CRTC first.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
src/sna/sna_display.c

index 89767ed..747d261 100644 (file)
@@ -4929,9 +4929,37 @@ fixup_flip:
                }
                arg.reserved = 0;
 
+retry_flip:
                DBG(("%s: crtc %d id=%d, pipe=%d  --> fb %d\n",
                     __FUNCTION__, i, crtc->id, crtc->pipe, arg.fb_id));
                if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
+                       ERR(("%s: pageflip failed with err=%d\n", __FUNCTION__, errno));
+
+                       if (errno == EBUSY) {
+                               struct drm_mode_crtc mode;
+
+                               memset(&mode, 0, sizeof(mode));
+                               mode.crtc_id = crtc->id;
+                               drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode);
+
+                               DBG(("%s: crtc=%d, valid?=%d, fb attached?=%d, expected=%d\n",
+                                    __FUNCTION__,
+                                    mode.crtc_id, mode.mode_valid,
+                                    mode.fb_id, fb_id(crtc->bo)));
+
+                               if (mode.fb_id != fb_id(crtc->bo))
+                                       goto fixup_flip;
+
+                               if (count == 0)
+                                       return 0;
+
+                               DBG(("%s: throttling on busy flip / waiting for kernel to catch up\n", __FUNCTION__));
+                               drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_THROTTLE, 0);
+                               sna->kgem.need_throttle = false;
+
+                               goto retry_flip;
+                       }
+
                        xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
                                   "page flipping failed, on CRTC:%d (pipe=%d), disabling %s page flips\n",
                                   crtc->id, crtc->pipe, data ? "synchronous": "asynchronous");