glx/dri2: add and use new driver hook flush_with_flags

This commit is contained in:
Marek Olšák 2012-11-23 18:31:42 +01:00
parent 5b7e9b7360
commit 4a486f8bf2
5 changed files with 123 additions and 53 deletions

View File

@ -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);
};

View File

@ -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 (psc->f && psc->f->base.version >= 4) {
unsigned flags = flush ? __DRI2_FLUSH_CONTEXT : 0;
__DRIcontext *ctx = dri2GetCurrentContext();
if (flush) {
glFlush();
}
if (psc->f) {
struct glx_context *gc = __glXGetCurrentContext();
if (gc) {
(*psc->f->flush)(priv->driDrawable);
if (ctx) {
(*psc->f->flush_with_flags)(ctx, priv->driDrawable, flags,
__DRI2_THROTTLE_SWAPBUFFER);
}
}
else {
if (flush) {
glFlush();
}
dri2Throttle(psc, priv, __DRI2_THROTTLE_SWAPBUFFER);
if (psc->f) {
struct glx_context *gc = __glXGetCurrentContext();
split_counter(target_msc, &target_msc_hi, &target_msc_lo);
split_counter(divisor, &divisor_hi, &divisor_lo);
split_counter(remainder, &remainder_hi, &remainder_lo);
if (gc) {
(*psc->f->flush)(priv->driDrawable);
}
}
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);
dri2Throttle(psc, priv, __DRI2_THROTTLE_SWAPBUFFER);
}
ret = dri2XcbSwapBuffers(pdraw->psc->dpy, pdraw,
target_msc, divisor, remainder);
}
if (psc->show_fps) {

View File

@ -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,

View File

@ -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,
};

View File

@ -193,7 +193,7 @@ radeonDRI2Flush(__DRIdrawable *drawable)
}
static const struct __DRI2flushExtensionRec radeonFlushExtension = {
{ __DRI2_FLUSH, __DRI2_FLUSH_VERSION },
{ __DRI2_FLUSH, 3 },
radeonDRI2Flush,
dri2InvalidateDrawable,
};