[PATCH v2 0/8] PRIME Synchronization

Alex Goins agoins at nvidia.com
Tue Jan 5 13:55:58 PST 2016

Hello all,

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 mailing list