[PATCH v2 0/8] PRIME Synchronization
agoins at nvidia.com
Tue Jan 5 13:55:58 PST 2016
These patches change the xserver to support setting up PRIME with double
buffering, and implement double buffered PRIME sink support in the
modesetting driver. In addition to these changes, I've upstreamed a couple
of patches to the i915 DRM driver that mesh with these, and have
implemented double buffered PRIME source support in the NVIDIA proprietary
driver (pending release.)
After the last discussion I tried various solutions to avoid polling on
vblank events when the system is idle, including having the sink/slave
register damage directly on the master screen pixmap's drawable and use
that to retry, or having the source/master retry presentation directly in
response to damage then explicitly requesting a flip from the sink. The
former fails to take into account cursor movement and breaks with
DAMAGE_VALIDATE_ENABLE, while the latter causes incomplete drawing because
it doesn't allow draw calls / damage to accumulate after receiving the
first. The solution I eventually came to involves retrying after the next
vblank after receiving damage. Ideally it would retry just before the next
vblank leaving just enough time to present and flip, but it's unlikely that
that could be achieved reliably at this level.
In this version of the patch set, aside from style changes, master screen
pixmap damage tracking was added as a power saving measure when the system
is idle. Instead of polling each vblank, it can now use new ABI functions
SharedPixmapNotifyDamage and RequestSharedPixmapNotifyDamage to only retry
on the vblank after mscreenpix receives damage.
After a call to master->RequestSharedPixmapNotifyDamage(ppix), when the
master receives damage on the mscreenpix tracked by ppix, it will call
slave->SharedPixmapNotifyDamage(ppix). The slave now uses
SharedPixmapNotifyDamage() to schedule the vblank interrupt instead of
doing it immediate after PresentSharedPixmap() (formerly
PresentTrackedFlippingPixmap()) fails. If RequestSharedPixmapNotifyDamage()
isn't available, it falls back to the old behavior.
Since Michel asked, here is more clarification on the distinction between
the existing (Start/Stop)PixmapTracking functions and the new
(Start/Stop)FlippingPixmapTracking functions added by this patch series:
(Start/Stop)PixmapTracking allow you to specify a single shared
buffer to track a master screen pixmap, and allow the master to
do whatever it needs to setup/teardown single buffered pixmap
tracking. Presenting on the shared buffer is driven internally by
the master. So, you could imagine that StartPixmapTracking might
schedule a timer or register damage tracking to present to the shared
buffer at an appropriate time.
(Start/Stop)FlippingPixmapTracking allow you to specify two shared
buffers to track a single master screen pixmap, and allow the master
to do whatever it needs to setup/teardown double buffered pixmap
tracking. Presenting on the shared buffer is driven by the slave,
via PresentTrackedFlippingPixmap(). It's the slave's responsibility
to ensure that this is done in time with its vblank. So, the sort of
work done by StartPixmapTracking to implicitly schedule presentation
to a shared buffer wouldn't be applicable here.
It would be theoretically possible to implement the functionality of
(Start/Stop)FlippingPixmapTracking by modifying
(Start/Stop)PixmapTracking to work this way with multiple calls, but I
think that would be flawed semantically. Today, I would expect the two
calls to StartPixmapTracking() to set up two independent shared pixmaps
tracking the same master screen pixmap, with presentation driven
internally. For example, multiple DisplayLink dongles working as PRIME
sinks all fed by the same PRIME source.
To do away with (Start/Stop)FlippingPixmapTracking, the semantics of
these existing functions would have to change, such that on the first
call it would have presentation driven internally, and on the second call
presentation would be driven externally. I've been trying to avoid
changing the semantics of existing paths. Moreover, this implicit
declaration of intent to use double buffered pixmap tracking would result
in wasteful setup and teardown between the first and second call, while
also being more error prone than explicit setup.
Updated content from last cover letter below.
They require the addition of a few ABI functions in pScreen:
(Enable/Disable)SharedPixmapFlipping - Functions to enable or disable
double buffered PRIME on the sink.
(Start/Stop)FlippingPixmapTracking - The double buffered counterparts
of (Start/Stop)PixmapTracking on the source.
PresentSharedPixmap - A function exposed by the source driver for the X
server or sink driver to call to request a present on a given shared
pixmap. This way, presenting can be driven by the sink's vblank
instead of a timer or similar mechanism in the source.
SharedPixmapNotifyDamage and RequestSharedPixmapNotifyDamage - OPTIONAL
(even for double-buffered PRIME) functions exposed by the sink driver
and the source driver, respectively. By calling
master->RequestSharedPixmapNotifyDamage(ppix), the sink driver can
request for the source driver to call
slave->SharedPixmapNotifyDamage(ppix) in response to damage on the
master screen pixmap tracked by ppix.
The user may enable or disable PRIME Synchronization / Double Buffering via
an output property:
'xrandr --output <output> --set "PRIME Synchronization" <0 or 1>'
If either the sink or the source do not present the required ABI functions,
it will gracefully fall back to single buffered PRIME.
In its pageflip/vblank event handler, the sink driver requests a present
from the source using the new X ABI function master->PresentSharedPixmap().
If the call returns successfully, it uses drmModePageFlip() to flip to the
updated buffer. PresentSharedPixmap() can fail, in most cases because
mscreenpix hasn't been damaged and a presentation would be wasteful. If it
fails and master->RequestSharedPixmapNotifyDamage() is available, the sink
will use it to try again on the next vblank after the master screen pixmap
is damaged. If it isn't available, the sink will just poll on each vblank
until PresentSharedPixmap() succeeds.
Some background on the DRM patches:
When the source driver presents on a given buffer, it first attaches a
fence. The source driver is responsible for either using software
signaling or hardware semaphore-backed fences to ensure the fence is
signaled when the present is finished. If the sink's DRM driver
implements fencing in the flipping path, it will guarantee that that
flip won't occur until the present has finished.
This means that DRM drivers that don't implement fencing in their
flipping paths won't be able to guarantee 100% tear-free PRIME with my
X patches. However, the good news is that even without fencing, tearing
is rare. Generally presenting finishes before the next vblank, so there
is no need to wait on the fence. The X patches are a drastic
improvement with or without fencing, but the fencing is nonetheless
important to guarantee tear-free under all conditions.
Thanks, Alex @ NVIDIA Linux Driver Team
Alex Goins (8):
xf86: Add PRIME flipping functions to ScreenRec
randr/xf86: Add PRIME Synchronization / Double Buffer
randr: Add ability to turn PRIME sync off
randr: Cleanup rrSetupPixmapSharing()
modesetting: Properly clean up w/ PRIME syncing
modesetting: Implement PRIME syncing as a sink
modesetting: Fix mmap leak in scanout_pixmap_cpu
modesetting: Suspend and resume flipping with DPMS
hw/xfree86/drivers/modesetting/driver.c | 69 +++++++
hw/xfree86/drivers/modesetting/drmmode_display.c | 240 ++++++++++++++++++++++-
hw/xfree86/drivers/modesetting/drmmode_display.h | 14 ++
hw/xfree86/modes/xf86Crtc.h | 4 +
hw/xfree86/modes/xf86RandR12.c | 4 +-
include/scrnintstr.h | 28 +++
randr/randrstr.h | 2 +
randr/rrcrtc.c | 108 ++++++++--
randr/rrprovider.c | 45 +++++
9 files changed, 493 insertions(+), 21 deletions(-)
More information about the xorg-devel