Skip to content
  • Mario Kleiner's avatar
    drm/vblank: Add support for precise vblank timestamping. · 27641c3f
    Mario Kleiner authored
    
    
    The DRI2 swap & sync implementation needs precise
    vblank counts and precise timestamps corresponding
    to those vblank counts. For conformance to the OpenML
    OML_sync_control extension specification the DRM
    timestamp associated with a vblank count should
    correspond to the start of video scanout of the first
    scanline of the video frame following the vblank
    interval for that vblank count.
    
    Therefore we need to carry around precise timestamps
    for vblanks. Currently the DRM and KMS drivers generate
    timestamps ad-hoc via do_gettimeofday() in some
    places. The resulting timestamps are sometimes not
    very precise due to interrupt handling delays, they
    don't conform to OML_sync_control and some are wrong,
    as they aren't taken synchronized to the vblank.
    
    This patch implements support inside the drm core
    for precise and robust timestamping. It consists
    of the following interrelated pieces.
    
    1. Vblank timestamp caching:
    
    A per-crtc ringbuffer stores the most recent vblank
    timestamps corresponding to vblank counts.
    
    The ringbuffer can be read out lock-free via the
    accessor function:
    
    struct timeval timestamp;
    vblankcount = drm_vblank_count_and_time(dev, crtcid, &timestamp).
    
    The function returns the current vblank count and
    the corresponding timestamp for start of video
    scanout following the vblank interval. It can be
    used anywhere between enclosing drm_vblank_get(dev, crtcid)
    and drm_vblank_put(dev,crtcid) statements. It is used
    inside the drmWaitVblank ioctl and in the vblank event
    queueing and handling. It should be used by kms drivers for
    timestamping of bufferswap completion.
    
    The timestamp ringbuffer is reinitialized each time
    vblank irq's get reenabled in drm_vblank_get()/
    drm_update_vblank_count(). It is invalidated when
    vblank irq's get disabled.
    
    The ringbuffer is updated inside drm_handle_vblank()
    at each vblank irq.
    
    2. Calculation of precise vblank timestamps:
    
    drm_get_last_vbltimestamp() is used to compute the
    timestamp for the end of the most recent vblank (if
    inside active scanout), or the expected end of the
    current vblank interval (if called inside a vblank
    interval). The function calls into a new optional kms
    driver entry point dev->driver->get_vblank_timestamp()
    which is supposed to provide the precise timestamp.
    If a kms driver doesn't implement the entry point or
    if the call fails, a simple do_gettimeofday() timestamp
    is returned as crude approximation of the true vblank time.
    
    A new drm module parameter drm.timestamp_precision_usec
    allows to disable high precision timestamps (if set to
    zero) or to specify the maximum acceptable error in
    the timestamps in microseconds.
    
    Kms drivers could implement their get_vblank_timestamp()
    function in a gpu specific way, as long as returned
    timestamps conform to OML_sync_control, e.g., by use
    of gpu specific hardware timestamps.
    
    Optionally, kms drivers can simply wrap and use the new
    utility function drm_calc_vbltimestamp_from_scanoutpos().
    This function calls a new optional kms driver function
    dev->driver->get_scanout_position() which returns the
    current horizontal and vertical video scanout position
    of the crtc. The scanout position together with the
    drm_display_timing of the current video mode is used
    to calculate elapsed time relative to start of active scanout
    for the current video frame. This elapsed time is subtracted
    from the current do_gettimeofday() time to get the timestamp
    corresponding to start of video scanout. Currently
    non-interlaced, non-doublescan video modes, with or
    without panel scaling are handled correctly. Interlaced/
    doublescan modes are tbd in a future patch.
    
    3. Filtering of redundant vblank irq's and removal of
    some race-conditions in the vblank irq enable/disable path:
    
    Some gpu's (e.g., Radeon R500/R600) send spurious vblank
    irq's outside the vblank if vblank irq's get reenabled.
    These get detected by use of the vblank timestamps and
    filtered out to avoid miscounting of vblanks.
    
    Some race-conditions between the vblank irq enable/disable
    functions, the vblank irq handler and the gpu itself (updating
    its hardware vblank counter in the "wrong" moment) are
    fixed inside vblank_disable_and_save() and
    drm_update_vblank_count() by use of the vblank timestamps and
    a new spinlock dev->vblank_time_lock.
    
    The time until vblank irq disable is now configurable via
    a new drm module parameter drm.vblankoffdelay to allow
    experimentation with timeouts that are much shorter than
    the current 5 seconds and should allow longer vblank off
    periods for better power savings.
    
    Followup patches will use these new functions to
    implement precise timestamping for the intel and radeon
    kms drivers.
    
    Signed-off-by: default avatarMario Kleiner <mario.kleiner@tuebingen.mpg.de>
    Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
    27641c3f