present: Fix inaccurate PresentCompleteNotify timing for TearFree
The timing of PresentCompleteNotify events is inaccurate when a driver uses TearFree because there's no way to know exactly when a presentation will appear on the display without receiving a notification directly from the driver indicating that the TearFree flip containing a presentation's pixmap is actually visible on the display. To fix the inaccurate PresentCompleteNotify timing, make use of the new assumption that drivers which export TearFree permit a NULL pixmap to be passed to their flip callback in order to make a presentation track the exact TearFree flip responsible for rendering it onto the display. Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com> Acked-by: Martin Roukala <martin.roukala@mupuf.org>
This commit is contained in:
parent
d4bd39f1a5
commit
1fab978a95
|
@ -646,31 +646,49 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
|
||||||
|
|
||||||
present_execute_copy(vblank, crtc_msc);
|
present_execute_copy(vblank, crtc_msc);
|
||||||
|
|
||||||
/* The presentation will be visible at the next vblank with TearFree, so
|
/* With TearFree, there's no way to tell exactly when the presentation
|
||||||
* the PresentComplete notification needs to be sent at the next vblank.
|
* will be visible except by waiting for a notification from the kernel
|
||||||
* If TearFree is already flipping then the presentation will be visible
|
* driver indicating that the page flip is complete. This is because the
|
||||||
* at the *next* next vblank.
|
* CRTC's MSC can change while the target MSC is calculated and even
|
||||||
|
* while the page flip IOCTL is sent to the kernel due to scheduling
|
||||||
|
* delays and/or unfortunate timing. Even worse, a page flip isn't
|
||||||
|
* actually guaranteed to be finished after one vblank; it may be
|
||||||
|
* several MSCs until a flip actually finishes depending on delays and
|
||||||
|
* load in hardware.
|
||||||
|
*
|
||||||
|
* So, to get a notification from the driver with TearFree active, the
|
||||||
|
* driver expects a present_flip() call with a NULL pixmap to indicate
|
||||||
|
* that this is a fake flip for a pixmap that's already been copied to
|
||||||
|
* the primary scanout, which will then be flipped by TearFree. TearFree
|
||||||
|
* will then send a notification once the flip containing this pixmap is
|
||||||
|
* complete.
|
||||||
|
*
|
||||||
|
* If the fake flip attempt fails, then fall back to just enqueuing a
|
||||||
|
* vblank event targeting the next MSC.
|
||||||
*/
|
*/
|
||||||
if (!vblank->queued) {
|
if (!vblank->queued &&
|
||||||
|
vblank->reason >= PRESENT_FLIP_REASON_DRIVER_TEARFREE) {
|
||||||
uint64_t completion_msc = crtc_msc + 1;
|
uint64_t completion_msc = crtc_msc + 1;
|
||||||
|
|
||||||
switch (vblank->reason) {
|
/* If TearFree is already flipping then the presentation will be
|
||||||
case PRESENT_FLIP_REASON_DRIVER_TEARFREE_FLIPPING:
|
* visible at the *next* next vblank. This calculation only matters
|
||||||
if (vblank->exec_msc < crtc_msc)
|
* for the vblank event fallback.
|
||||||
|
*/
|
||||||
|
if (vblank->reason == PRESENT_FLIP_REASON_DRIVER_TEARFREE_FLIPPING &&
|
||||||
|
vblank->exec_msc < crtc_msc)
|
||||||
completion_msc++;
|
completion_msc++;
|
||||||
case PRESENT_FLIP_REASON_DRIVER_TEARFREE:
|
|
||||||
if (Success == screen_priv->queue_vblank(screen,
|
/* Try the fake flip first and then fall back to a vblank event */
|
||||||
|
if (present_flip(vblank->crtc, vblank->event_id, 0, NULL, TRUE) ||
|
||||||
|
Success == screen_priv->queue_vblank(screen,
|
||||||
window,
|
window,
|
||||||
vblank->crtc,
|
vblank->crtc,
|
||||||
vblank->event_id,
|
vblank->event_id,
|
||||||
completion_msc)) {
|
completion_msc)) {
|
||||||
/* Ensure present_execute_post() runs at the next MSC */
|
/* Ensure present_execute_post() runs at the next execution */
|
||||||
vblank->exec_msc = vblank->target_msc;
|
vblank->exec_msc = vblank->target_msc;
|
||||||
vblank->queued = TRUE;
|
vblank->queued = TRUE;
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vblank->queued) {
|
if (vblank->queued) {
|
||||||
|
|
Loading…
Reference in New Issue