From 4a486f8bf2ca3d88228f8313282289abe78bc2f8 Mon Sep 17 00:00:00 2001 From: Marek Olšák Date: Fri, 23 Nov 2012 18:31:42 +0100 Subject: glx/dri2: add and use new driver hook flush_with_flags --- include/GL/internal/dri_interface.h | 29 +++++- src/glx/dri2_glx.c | 141 +++++++++++++++++--------- src/mesa/drivers/dri/intel/intel_screen.c | 2 +- src/mesa/drivers/dri/nouveau/nouveau_screen.c | 2 +- src/mesa/drivers/dri/radeon/radeon_screen.c | 2 +- 5 files changed, 123 insertions(+), 53 deletions(-) diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h index 1e0f1d07b3b..718b53beb88 100644 --- a/include/GL/internal/dri_interface.h +++ b/include/GL/internal/dri_interface.h @@ -267,7 +267,13 @@ struct __DRItexBufferExtensionRec { * Used by drivers that implement DRI2 */ #define __DRI2_FLUSH "DRI2_Flush" -#define __DRI2_FLUSH_VERSION 3 +#define __DRI2_FLUSH_VERSION 4 + +#define __DRI2_FLUSH_DRAWABLE (1 << 0) /* the drawable should be flushed. */ +#define __DRI2_FLUSH_CONTEXT (1 << 1) /* glFlush should be called */ + +enum __DRI2throttleReason; + struct __DRI2flushExtensionRec { __DRIextension base; void (*flush)(__DRIdrawable *drawable); @@ -281,6 +287,27 @@ struct __DRI2flushExtensionRec { * \since 3 */ void (*invalidate)(__DRIdrawable *drawable); + + /** + * This function reduces the number of flushes in the driver by combining + * several operations into one call. + * + * It can: + * - throttle + * - flush a drawable + * - flush a context + * + * \param context the context + * \param drawable the drawable to flush + * \param flags a combination of _DRI2_FLUSH_xxx flags + * \param throttle_reason the reason for throttling, 0 = no throttling + * + * \since 4 + */ + void (*flush_with_flags)(__DRIcontext *ctx, + __DRIdrawable *drawable, + unsigned flags, + enum __DRI2throttleReason throttle_reason); }; diff --git a/src/glx/dri2_glx.c b/src/glx/dri2_glx.c index 30f6913010a..a6ab1bd6683 100644 --- a/src/glx/dri2_glx.c +++ b/src/glx/dri2_glx.c @@ -509,6 +509,15 @@ dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust, return 1; } +static __DRIcontext * +dri2GetCurrentContext() +{ + struct glx_context *gc = __glXGetCurrentContext(); + struct dri2_context *dri2Ctx = (struct dri2_context *)gc; + + return dri2Ctx ? dri2Ctx->driContext : NULL; +} + /** * dri2Throttle - Request driver throttling * @@ -522,10 +531,7 @@ dri2Throttle(struct dri2_screen *psc, enum __DRI2throttleReason reason) { if (psc->throttle) { - struct glx_context *gc = __glXGetCurrentContext(); - struct dri2_context *dri2Ctx = (struct dri2_context *)gc; - __DRIcontext *ctx = - (dri2Ctx) ? dri2Ctx->driContext : NULL; + __DRIcontext *ctx = dri2GetCurrentContext(); psc->throttle->throttle(ctx, draw->driDrawable, reason); } @@ -550,14 +556,25 @@ __dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, xrect.width = width; xrect.height = height; - if (flush) { - glFlush(); + if (psc->f && psc->f->base.version >= 4) { + unsigned flags = flush ? __DRI2_FLUSH_CONTEXT : 0; + __DRIcontext *ctx = dri2GetCurrentContext(); + + if (ctx) { + (*psc->f->flush_with_flags)(ctx, priv->driDrawable, flags, reason); + } } + else { + if (flush) { + glFlush(); + } - if (psc->f) - (*psc->f->flush) (priv->driDrawable); + if (psc->f) { + (*psc->f->flush) (priv->driDrawable); + } - dri2Throttle(psc, priv, reason); + dri2Throttle(psc, priv, reason); + } region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, @@ -733,6 +750,50 @@ static void show_fps(struct dri2_drawable *draw) } } +static int64_t +dri2XcbSwapBuffers(Display *dpy, + __GLXDRIdrawable *pdraw, + int64_t target_msc, + int64_t divisor, + int64_t remainder) +{ + xcb_dri2_swap_buffers_cookie_t swap_buffers_cookie; + xcb_dri2_swap_buffers_reply_t *swap_buffers_reply; + uint32_t target_msc_hi, target_msc_lo; + uint32_t divisor_hi, divisor_lo; + uint32_t remainder_hi, remainder_lo; + int64_t ret = 0; + xcb_connection_t *c = XGetXCBConnection(dpy); + + split_counter(target_msc, &target_msc_hi, &target_msc_lo); + split_counter(divisor, &divisor_hi, &divisor_lo); + split_counter(remainder, &remainder_hi, &remainder_lo); + + swap_buffers_cookie = + xcb_dri2_swap_buffers_unchecked(c, pdraw->xDrawable, + target_msc_hi, target_msc_lo, + divisor_hi, divisor_lo, + remainder_hi, remainder_lo); + + /* Immediately wait on the swapbuffers reply. If we didn't, we'd have + * to do so some time before reusing a (non-pageflipped) backbuffer. + * Otherwise, the new rendering could get ahead of the X Server's + * dispatch of the swapbuffer and you'd display garbage. + * + * We use XSync() first to reap the invalidate events through the event + * filter, to ensure that the next drawing doesn't use an invalidated + * buffer. + */ + XSync(dpy, False); + + swap_buffers_reply = + xcb_dri2_swap_buffers_reply(c, swap_buffers_cookie, NULL); + ret = merge_counter(swap_buffers_reply->swap_hi, + swap_buffers_reply->swap_lo); + free(swap_buffers_reply); + return ret; +} + static int64_t dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, int64_t remainder, Bool flush) @@ -742,7 +803,7 @@ dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display; - CARD64 ret = 0; + int64_t ret = 0; /* Check we have the right attachments */ if (!priv->have_back) @@ -753,51 +814,33 @@ dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, __dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height, __DRI2_THROTTLE_SWAPBUFFER, flush); } else { - xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); - xcb_dri2_swap_buffers_cookie_t swap_buffers_cookie; - xcb_dri2_swap_buffers_reply_t *swap_buffers_reply; - uint32_t target_msc_hi, target_msc_lo; - uint32_t divisor_hi, divisor_lo; - uint32_t remainder_hi, remainder_lo; - - if (flush) { - glFlush(); + if (psc->f && psc->f->base.version >= 4) { + unsigned flags = flush ? __DRI2_FLUSH_CONTEXT : 0; + __DRIcontext *ctx = dri2GetCurrentContext(); + + if (ctx) { + (*psc->f->flush_with_flags)(ctx, priv->driDrawable, flags, + __DRI2_THROTTLE_SWAPBUFFER); + } } + else { + if (flush) { + glFlush(); + } - if (psc->f) { - struct glx_context *gc = __glXGetCurrentContext(); + if (psc->f) { + struct glx_context *gc = __glXGetCurrentContext(); - if (gc) { - (*psc->f->flush)(priv->driDrawable); + if (gc) { + (*psc->f->flush)(priv->driDrawable); + } } + + dri2Throttle(psc, priv, __DRI2_THROTTLE_SWAPBUFFER); } - dri2Throttle(psc, priv, __DRI2_THROTTLE_SWAPBUFFER); - - split_counter(target_msc, &target_msc_hi, &target_msc_lo); - split_counter(divisor, &divisor_hi, &divisor_lo); - split_counter(remainder, &remainder_hi, &remainder_lo); - - swap_buffers_cookie = - xcb_dri2_swap_buffers_unchecked(c, pdraw->xDrawable, - target_msc_hi, target_msc_lo, - divisor_hi, divisor_lo, - remainder_hi, remainder_lo); - /* Immediately wait on the swapbuffers reply. If we didn't, we'd have - * to do so some time before reusing a (non-pageflipped) backbuffer. - * Otherwise, the new rendering could get ahead of the X Server's - * dispatch of the swapbuffer and you'd display garbage. - * - * We use XSync() first to reap the invalidate events through the event - * filter, to ensure that the next drawing doesn't use an invalidated - * buffer. - */ - XSync(pdraw->psc->dpy, False); - swap_buffers_reply = - xcb_dri2_swap_buffers_reply(c, swap_buffers_cookie, NULL); - ret = merge_counter(swap_buffers_reply->swap_hi, - swap_buffers_reply->swap_lo); - free(swap_buffers_reply); + ret = dri2XcbSwapBuffers(pdraw->psc->dpy, pdraw, + target_msc, divisor, remainder); } if (psc->show_fps) { diff --git a/src/mesa/drivers/dri/intel/intel_screen.c b/src/mesa/drivers/dri/intel/intel_screen.c index da231270bc1..e0fe8c186cb 100644 --- a/src/mesa/drivers/dri/intel/intel_screen.c +++ b/src/mesa/drivers/dri/intel/intel_screen.c @@ -188,7 +188,7 @@ intelDRI2Flush(__DRIdrawable *drawable) } static const struct __DRI2flushExtensionRec intelFlushExtension = { - .base = { __DRI2_FLUSH, __DRI2_FLUSH_VERSION }, + .base = { __DRI2_FLUSH, 3 }, .flush = intelDRI2Flush, .invalidate = dri2InvalidateDrawable, diff --git a/src/mesa/drivers/dri/nouveau/nouveau_screen.c b/src/mesa/drivers/dri/nouveau/nouveau_screen.c index dc6d758f771..ca39fff807a 100644 --- a/src/mesa/drivers/dri/nouveau/nouveau_screen.c +++ b/src/mesa/drivers/dri/nouveau/nouveau_screen.c @@ -216,7 +216,7 @@ nouveau_drawable_flush(__DRIdrawable *draw) } static const struct __DRI2flushExtensionRec nouveau_flush_extension = { - { __DRI2_FLUSH, __DRI2_FLUSH_VERSION }, + { __DRI2_FLUSH, 3 }, nouveau_drawable_flush, dri2InvalidateDrawable, }; diff --git a/src/mesa/drivers/dri/radeon/radeon_screen.c b/src/mesa/drivers/dri/radeon/radeon_screen.c index 2e6cf3cb5c0..7d1c0be4365 100644 --- a/src/mesa/drivers/dri/radeon/radeon_screen.c +++ b/src/mesa/drivers/dri/radeon/radeon_screen.c @@ -193,7 +193,7 @@ radeonDRI2Flush(__DRIdrawable *drawable) } static const struct __DRI2flushExtensionRec radeonFlushExtension = { - { __DRI2_FLUSH, __DRI2_FLUSH_VERSION }, + { __DRI2_FLUSH, 3 }, radeonDRI2Flush, dri2InvalidateDrawable, }; -- cgit v1.2.3