diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2014-05-07 17:49:15 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2014-05-07 21:53:46 +0100 |
commit | 7d516589ba9d0325e57e08d41becff64f81e2d00 (patch) | |
tree | 0b1b0034f7688b5e9b7325c7cf3ec87f4d7a4199 | |
parent | 18416b5162e6d6e5415916c55c935b08c980d7f3 (diff) |
sna/dri: Implement TripleBuffering using DRI2SwapLimit
An addition to DRI2 that was overlooked at the time, was the support
added for having multiple outstanding swap requests in the core. The
importance of this is that we can then send the SwapComplete reply after
the pageflip is completed and not before as we currently do to fake
triple buffering - in clear violation of OML_sync_control.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/sna_dri.c | 213 |
1 files changed, 159 insertions, 54 deletions
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c index 89d707ae..f30770fb 100644 --- a/src/sna/sna_dri.c +++ b/src/sna/sna_dri.c @@ -55,6 +55,17 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #error DRI2 version supported by the Xserver is too old #endif +#if DRI2INFOREC_VERSION < 6 +#define XORG_CAN_TRIPLE_BUFFER 0 +#else +#define XORG_CAN_TRIPLE_BUFFER 1 +static Bool +sna_dri_swap_limit_validate(DrawablePtr draw, int swap_limit) +{ + return swap_limit >= 1; +} +#endif + #if DRI2INFOREC_VERSION < 10 #undef USE_ASYNC_SWAP #define USE_ASYNC_SWAP 0 @@ -969,6 +980,7 @@ sna_dri_window_set_chain(WindowPtr win, { DBG(("%s: head now %p\n", __FUNCTION__, chain)); assert(win->drawable.type == DRAWABLE_WINDOW); + assert(sna_dri_window_get_chain(win) != chain); ((void **)__get_private(win, sna_window_key))[1] = chain; } @@ -1121,6 +1133,11 @@ sna_dri_page_flip(struct sna *sna, struct sna_dri_frame_event *info) get_private(info->back)->bo = tmp.bo; sna->dri.flip_pending = info; + +#if XORG_CAN_TRIPLE_BUFFER + DRI2SwapLimit(info->draw, 1 + (info->type == DRI2_FLIP_THROTTLE)); +#endif + return true; } @@ -1304,48 +1321,53 @@ static void chain_swap(struct sna *sna, DBG(("%s: chaining type=%d\n", __FUNCTION__, chain->type)); switch (chain->type) { case DRI2_SWAP_THROTTLE: - break; - default: - return; - } - - DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__)); - - if (sna->mode.shadow_flip && !sna->mode.shadow_damage) { - /* recursed from wait_for_shadow(), simply requeue */ - DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__)); - chain->type = DRI2_SWAP; + DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__)); + if (sna->mode.shadow_flip && !sna->mode.shadow_damage) { + /* recursed from wait_for_shadow(), simply requeue */ + DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__)); + chain->type = DRI2_SWAP; - VG_CLEAR(vbl); - vbl.request.type = - DRM_VBLANK_RELATIVE | - DRM_VBLANK_EVENT; - vbl.request.sequence = 1; - vbl.request.signal = (unsigned long)chain; + VG_CLEAR(vbl); + vbl.request.type = + DRM_VBLANK_RELATIVE | + DRM_VBLANK_EVENT; + vbl.request.sequence = 1; + vbl.request.signal = (unsigned long)chain; - if (!sna_wait_vblank(sna, &vbl, chain->pipe)) - return; + if (!sna_wait_vblank(sna, &vbl, chain->pipe)) + return; - DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno)); - } else { - chain->bo = __sna_dri_copy_region(sna, draw, NULL, - chain->back, chain->front, true); + DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno)); + } else { + chain->bo = __sna_dri_copy_region(sna, draw, NULL, + chain->back, chain->front, true); + } + case DRI2_SWAP: + break; + default: + return; } - DRI2SwapComplete(chain->client, draw, - frame, tv_sec, tv_usec, - DRI2_BLIT_COMPLETE, - chain->client ? chain->event_complete : NULL, chain->event_data); - VG_CLEAR(vbl); vbl.request.type = DRM_VBLANK_RELATIVE | - DRM_VBLANK_NEXTONMISS | DRM_VBLANK_EVENT; - vbl.request.sequence = 0; + vbl.request.sequence = 1; vbl.request.signal = (unsigned long)chain; - if (sna_wait_vblank(sna, &vbl, chain->pipe)) + if (sna_wait_vblank(sna, &vbl, chain->pipe)) { + DRI2SwapComplete(chain->client, draw, + frame, tv_sec, tv_usec, + DRI2_BLIT_COMPLETE, + chain->client ? chain->event_complete : NULL, chain->event_data); sna_dri_frame_event_info_free(sna, draw, chain); + } else { +#if !XORG_CAN_TRIPLE_BUFFER + DRI2SwapComplete(chain->client, draw, + frame, tv_sec, tv_usec, + DRI2_BLIT_COMPLETE, + chain->client ? chain->event_complete : NULL, chain->event_data); +#endif + } } static bool sna_dri_blit_complete(struct sna *sna, @@ -1432,6 +1454,18 @@ void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event) DBG(("%s: %d complete, frame=%d tv=%d.%06d\n", __FUNCTION__, info->type, event->sequence, event->tv_sec, event->tv_usec)); + +#if XORG_CAN_TRIPLE_BUFFER + if (!sna_dri_blit_complete(sna, info)) + return; + + DRI2SwapComplete(info->client, + draw, event->sequence, + event->tv_sec, event->tv_usec, + DRI2_BLIT_COMPLETE, + info->client ? info->event_complete : NULL, + info->event_data); +#endif break; case DRI2_WAITMSC: @@ -1448,6 +1482,7 @@ void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event) } if (info->chain) { + assert(info->chain != info); sna_dri_remove_frame_event((WindowPtr)draw, info); chain_swap(sna, draw, event->sequence, event->tv_sec, event->tv_usec, @@ -1475,10 +1510,7 @@ sna_dri_immediate_blit(struct sna *sna, event)); if (sync) { - info->type = DRI2_SWAP_THROTTLE; if (sna_dri_window_get_chain((WindowPtr)draw) == info) { - drmVBlank vbl; - DBG(("%s: no pending blit, starting chain\n", __FUNCTION__)); @@ -1487,24 +1519,59 @@ sna_dri_immediate_blit(struct sna *sna, info->front, true); if (event) { - DRI2SwapComplete(info->client, draw, 0, 0, 0, - DRI2_BLIT_COMPLETE, - info->event_complete, - info->event_data); + drmVBlank vbl; + + info->type = DRI2_SWAP_THROTTLE; VG_CLEAR(vbl); vbl.request.type = DRM_VBLANK_RELATIVE | - DRM_VBLANK_NEXTONMISS | DRM_VBLANK_EVENT; - vbl.request.sequence = 0; + vbl.request.sequence = 1; vbl.request.signal = (unsigned long)info; ret = !sna_wait_vblank(sna, &vbl, info->pipe); +#if XORG_CAN_TRIPLE_BUFFER + if (ret) + DRI2SwapLimit(draw, 2); +#endif + if (!XORG_CAN_TRIPLE_BUFFER || !ret) + DRI2SwapComplete(info->client, draw, 0, 0, 0, + DRI2_BLIT_COMPLETE, + info->event_complete, + info->event_data); } } else { DBG(("%s: pending blit, chained\n", __FUNCTION__)); ret = true; } +#if XORG_CAN_TRIPLE_BUFFER + } else if (event) { + if (sna_dri_window_get_chain((WindowPtr)draw) == info) { + drmVBlank vbl; + + info->type = DRI2_SWAP_THROTTLE; + info->bo = __sna_dri_copy_region(sna, draw, NULL, + info->back, info->front, false); + + VG_CLEAR(vbl); + vbl.request.type = + DRM_VBLANK_RELATIVE | + DRM_VBLANK_EVENT; + vbl.request.sequence = 1; + vbl.request.signal = (unsigned long)info; + ret = !sna_wait_vblank(sna, &vbl, info->pipe); + if (ret) + DRI2SwapLimit(draw, 2); + else + DRI2SwapComplete(info->client, draw, 0, 0, 0, + DRI2_BLIT_COMPLETE, + info->event_complete, + info->event_data); + } else { + DBG(("%s: pending blit, chained\n", __FUNCTION__)); + ret = true; + } +#endif } else { DBG(("%s: immediate blit\n", __FUNCTION__)); info->bo = __sna_dri_copy_region(sna, draw, NULL, @@ -1618,11 +1685,13 @@ sna_dri_flip_continue(struct sna *sna, struct sna_dri_frame_event *info) return false; sna_dri_flip_get_back(sna, info); +#if !XORG_CAN_TRIPLE_BUFFER DRI2SwapComplete(info->client, info->draw, 0, 0, 0, DRI2_FLIP_COMPLETE, info->client ? info->event_complete : NULL, info->event_data); +#endif } info->mode = 0; @@ -1653,6 +1722,23 @@ static void chain_flip(struct sna *sna) chain->bo = __sna_dri_copy_region(sna, chain->draw, NULL, chain->back, chain->front, true); +#if XORG_CAN_TRIPLE_BUFFER + { + drmVBlank vbl; + + VG_CLEAR(vbl); + + chain->type = DRI2_SWAP_WAIT; + vbl.request.type = + DRM_VBLANK_RELATIVE | + DRM_VBLANK_EVENT; + vbl.request.sequence = 1; + vbl.request.signal = (unsigned long)chain; + + if (!sna_wait_vblank(sna, &vbl, chain->pipe)) + return; + } +#endif DRI2SwapComplete(chain->client, chain->draw, 0, 0, 0, DRI2_BLIT_COMPLETE, chain->client ? chain->event_complete : NULL, chain->event_data); sna_dri_frame_event_info_free(sna, chain->draw, chain); @@ -1729,6 +1815,16 @@ static void sna_dri_flip_event(struct sna *sna, break; case DRI2_FLIP_THROTTLE: +#if XORG_CAN_TRIPLE_BUFFER + if (flip->draw) + DRI2SwapComplete(flip->client, flip->draw, + flip->fe_frame, + flip->fe_tv_sec, + flip->fe_tv_usec, + DRI2_FLIP_COMPLETE, + flip->client ? flip->event_complete : NULL, + flip->event_data); +#endif if (sna->dri.flip_pending) { sna_dri_frame_event_info_free(sna, flip->draw, flip); chain_flip(sna); @@ -1804,29 +1900,32 @@ get_current_msc_for_target(struct sna *sna, CARD64 target_msc, int pipe) return ret; } +#if !XORG_CAN_TRIPLE_BUFFER && XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0) static Bool find(pointer value, XID id, pointer cdata) { return TRUE; } +#endif static int use_triple_buffer(struct sna *sna, ClientPtr client) { - struct sna_client *priv; - if ((sna->flags & SNA_TRIPLE_BUFFER) == 0) return DRI2_FLIP; +#if XORG_CAN_TRIPLE_BUFFER + return DRI2_FLIP_THROTTLE; +#elif XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0) /* Hack: Disable triple buffering for compositors */ + { + struct sna_client *priv = sna_client(client); + if (priv->is_compositor == 0) + priv->is_compositor = + LookupClientResourceComplex(client, + CompositeClientWindowType+1, + find, NULL) ? DRI2_FLIP : DRI2_FLIP_THROTTLE; -#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0) - priv = sna_client(client); - if (priv->is_compositor == 0) - priv->is_compositor = - LookupClientResourceComplex(client, - CompositeClientWindowType+1, - find, NULL) ? DRI2_FLIP : DRI2_FLIP_THROTTLE; - - return priv->is_compositor; + return priv->is_compositor; + } #else return DRI2_FLIP_THROTTLE; #endif @@ -1919,9 +2018,11 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, if (info->type != DRI2_FLIP) { new_back: sna_dri_flip_get_back(sna, info); +#if !XORG_CAN_TRIPLE_BUFFER DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_EXCHANGE_COMPLETE, func, data); +#endif } out: DBG(("%s: target_msc=%lu\n", __FUNCTION__, (unsigned long)current_msc)); @@ -2010,6 +2111,10 @@ out: return false; } +#if XORG_CAN_TRIPLE_BUFFER + DRI2SwapLimit(draw, 1); +#endif + return true; } @@ -2345,10 +2450,10 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc, vbl.request.sequence += divisor; } + DBG(("%s: waiting until MSC=%llu\n", __FUNCTION__, (long long)vbl.request.sequence)); if (sna_wait_vblank(sna, &vbl, pipe)) goto out_free_info; - DBG(("%s: waiting until MSC=%llu\n", __FUNCTION__, (long long)vbl.request.sequence)); DRI2BlockClient(client, draw); return TRUE; @@ -2506,9 +2611,9 @@ bool sna_dri_open(struct sna *sna, ScreenPtr screen) driverNames[1] = info.driverName; #endif -#if DRI2INFOREC_VERSION >= 6 +#if XORG_CAN_TRIPLE_BUFFER info.version = 6; - info.SwapLimitValidate = NULL; + info.SwapLimitValidate = sna_dri_swap_limit_validate; info.ReuseBufferNotify = NULL; #endif |