diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h index 8d24e31..bd898d2 100644 --- a/include/GL/internal/dri_interface.h +++ b/include/GL/internal/dri_interface.h @@ -512,6 +512,17 @@ struct __DRIdrawableRec { */ void (*copySubBuffer)(__DRInativeDisplay *dpy, void *drawablePrivate, int x, int y, int w, int h); + + /** + * Like the screen version of getMSC, but also takes a drawable so that + * the appropriate pipe's counter can be retrieved. + * + * Get the number of vertical refreshes since some point in time before + * this function was first called (i.e., system start up). + * + * \since Internal API version 20070925. + */ + int (*getMSC)(__DRInativeDisplay *dpy, void *drawablePrivate, int64_t *msc); }; #endif diff --git a/src/glx/x11/glxcmds.c b/src/glx/x11/glxcmds.c index f52b71f..134afac 100644 --- a/src/glx/x11/glxcmds.c +++ b/src/glx/x11/glxcmds.c @@ -1889,14 +1889,32 @@ static int __glXGetVideoSyncSGI(unsigned int *count) if ( (gc != NULL) && gc->isDirect ) { __GLXscreenConfigs * const psc = GetGLXScreenConfigs( gc->currentDpy, gc->screen ); - if ( __glXExtensionBitIsEnabled( psc, SGI_video_sync_bit ) - && psc->driScreen.private && psc->driScreen.getMSC) { - int ret; - int64_t temp; - - ret = psc->driScreen.getMSC( psc->driScreen.private, & temp ); - *count = (unsigned) temp; - return (ret == 0) ? 0 : GLX_BAD_CONTEXT; + if ( __glXExtensionBitIsEnabled( psc, SGI_video_sync_bit ) + && psc->driScreen.private ) { + __DRIdrawable * const pdraw = + (*psc->driScreen.getDrawable)(gc->currentDpy, + gc->currentDrawable, + psc->driScreen.private); + /* + * Try to use the drawable's getMSC first so we get the right + * counter + */ + if ( (pdraw != NULL) && (pdraw->getMSC != NULL) ) { + int ret; + int64_t temp; + + ret = (*pdraw->getMSC)( psc->driScreen.private, pdraw->private, + & temp); + *count = (unsigned) temp; + return (ret == 0) ? 0 : GLX_BAD_CONTEXT; + } else if ( psc->driScreen.getMSC ) { /* fallback to screen */ + int ret; + int64_t temp; + + ret = psc->driScreen.getMSC( psc->driScreen.private, & temp ); + *count = (unsigned) temp; + return (ret == 0) ? 0 : GLX_BAD_CONTEXT; + } } } #else diff --git a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c index c30e66f..ae2db0a 100644 --- a/src/mesa/drivers/dri/common/dri_util.c +++ b/src/mesa/drivers/dri/common/dri_util.c @@ -31,6 +31,7 @@ #include "dri_util.h" #include "drm_sarea.h" +#include "vblank.h" #ifndef GLX_OML_sync_control typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRInativeDisplay *dpy, __DRIid drawable, int32_t *numerator, int32_t *denominator); @@ -639,6 +640,8 @@ static void *driCreateNewDrawable(__DRInativeDisplay *dpy, pdp->numBackClipRects = 0; pdp->pClipRects = NULL; pdp->pBackClipRects = NULL; + pdp->vblSeq = 0; + pdp->vblFlags = 0; pdp->display = dpy; pdp->screen = modes->screen; @@ -663,6 +666,7 @@ static void *driCreateNewDrawable(__DRInativeDisplay *dpy, pdraw->swapBuffersMSC = driSwapBuffersMSC; pdraw->frameTracking = NULL; pdraw->queryFrameTracking = driQueryFrameTracking; + pdraw->getMSC = driDrawableGetMSC; if (driCompareGLXAPIVersion (20060314) >= 0) pdraw->copySubBuffer = driCopySubBuffer; diff --git a/src/mesa/drivers/dri/common/dri_util.h b/src/mesa/drivers/dri/common/dri_util.h index 539d28d..cb3c5d3 100644 --- a/src/mesa/drivers/dri/common/dri_util.h +++ b/src/mesa/drivers/dri/common/dri_util.h @@ -308,6 +308,15 @@ struct __DRIdrawablePrivateRec { /*@}*/ /** + * \name Vertical blank tracking information + * Used for waiting on vertical blank events. + */ + /*@{*/ + unsigned int vblSeq; + unsigned int vblFlags; + /*@}*/ + + /** * Pointer to context to which this drawable is currently bound. */ __DRIcontextPrivate *driContextPriv; diff --git a/src/mesa/drivers/dri/common/vblank.c b/src/mesa/drivers/dri/common/vblank.c index e7ed545..6ab72b3 100644 --- a/src/mesa/drivers/dri/common/vblank.c +++ b/src/mesa/drivers/dri/common/vblank.c @@ -50,19 +50,24 @@ * currently always returns a \c sequence of type \c unsigned. * * \param priv Pointer to the DRI screen private struct. + * \param drawablePrivate pointer to the DRI drawable private struct * \param count Storage to hold MSC counter. * \return Zero is returned on success. A negative errno value * is returned on failure. */ -int driGetMSC32( __DRIscreenPrivate * priv, int64_t * count ) +int driDrawableGetMSC(__DRIscreenPrivate * priv, void *drawablePrivate, + int64_t * count) { drmVBlank vbl; int ret; + __DRIdrawablePrivate *dPriv = drawablePrivate; /* Don't wait for anything. Just get the current refresh count. */ vbl.request.type = DRM_VBLANK_RELATIVE; vbl.request.sequence = 0; + if ( dPriv->vblFlags & VBLANK_FLAG_SECONDARY ) + vbl.request.type |= DRM_VBLANK_SECONDARY; ret = drmWaitVBlank( priv->fd, &vbl ); *count = (int64_t)vbl.reply.sequence; @@ -70,6 +75,27 @@ int driGetMSC32( __DRIscreenPrivate * priv, int64_t * count ) return ret; } +/** + * Get the current MSC refresh counter. + * + * Stores the 64-bit count of vertical refreshes since some (arbitrary) + * point in time in \c count. Unless the value wraps around, which it + * may, it will never decrease. + * + * \warning This function is called from \c glXGetVideoSyncSGI, which expects + * a \c count of type \c unsigned (32-bit), and \c glXGetSyncValuesOML, which + * expects a \c count of type \c int64_t (signed 64-bit). The kernel ioctl + * currently always returns a \c sequence of type \c unsigned. + * + * \param priv Pointer to the DRI screen private struct. + * \param count Storage to hold MSC counter. + * \return Zero is returned on success. A negative errno value + * is returned on failure. + */ +int driGetMSC32( __DRIscreenPrivate * priv, int64_t * count ) +{ + return driDrawableGetMSC32(priv, NULL, count); +} /****************************************************************************/ /** @@ -124,6 +150,8 @@ int driWaitForMSC32( __DRIdrawablePrivate *priv, vbl.request.type = dont_wait ? DRM_VBLANK_RELATIVE : DRM_VBLANK_ABSOLUTE; vbl.request.sequence = next; + if ( priv->vblFlags & VBLANK_FLAG_SECONDARY ) + vbl.request.type |= DRM_VBLANK_SECONDARY; if ( drmWaitVBlank( priv->driScreenPriv->fd, &vbl ) != 0 ) { /* FIXME: This doesn't seem like the right thing to return here. @@ -257,7 +285,12 @@ void driDrawableInitVBlank( __DRIdrawablePrivate *priv, GLuint flags, { if ( priv->pdraw->swap_interval == (unsigned)-1 ) { /* Get current vertical blank sequence */ - drmVBlank vbl = { .request={ .type = DRM_VBLANK_RELATIVE, .sequence = 0 } }; + drmVBlank vbl; + + vbl.request.type = DRM_VBLANK_RELATIVE; + if ( flags & VBLANK_FLAG_SECONDARY ) + vbl.request.type |= DRM_VBLANK_SECONDARY; + vbl.request.sequence = 0; do_wait( &vbl, vbl_seq, priv->driScreenPriv->fd ); priv->pdraw->swap_interval = (flags & (VBLANK_FLAG_THROTTLE | diff --git a/src/mesa/drivers/dri/common/vblank.h b/src/mesa/drivers/dri/common/vblank.h index ec83adc..a9d720d 100644 --- a/src/mesa/drivers/dri/common/vblank.h +++ b/src/mesa/drivers/dri/common/vblank.h @@ -45,6 +45,8 @@ #define VBLANK_FLAG_SECONDARY (1U << 8) /* Wait for secondary vblank. */ +extern int driDrawableGetMSC(__DRIscreenPrivate * priv, void *drawablePrivate, + int64_t * count); extern int driGetMSC32( __DRIscreenPrivate * priv, int64_t * count ); extern int driWaitForMSC32( __DRIdrawablePrivate *priv, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t * msc ); diff --git a/src/mesa/drivers/dri/i965/intel_blit.c b/src/mesa/drivers/dri/i965/intel_blit.c index f88cbb2..a7604b9 100644 --- a/src/mesa/drivers/dri/i965/intel_blit.c +++ b/src/mesa/drivers/dri/i965/intel_blit.c @@ -76,7 +76,8 @@ void intelCopyBuffer( const __DRIdrawablePrivate *dPriv, if (!rect) { UNLOCK_HARDWARE( intel ); - driWaitForVBlank( dPriv, &intel->vbl_seq, intel->vblank_flags, & missed_target ); + driWaitForVBlank( dPriv, &dPriv->vblSeq, dPriv->vblFlags, + &missed_target ); LOCK_HARDWARE( intel ); } diff --git a/src/mesa/drivers/dri/i965/intel_buffers.c b/src/mesa/drivers/dri/i965/intel_buffers.c index d155c03..2b2bac0 100644 --- a/src/mesa/drivers/dri/i965/intel_buffers.c +++ b/src/mesa/drivers/dri/i965/intel_buffers.c @@ -33,6 +33,8 @@ #include "context.h" #include "framebuffer.h" #include "macros.h" +#include "utils.h" +#include "vblank.h" #include "swrast/swrast.h" GLboolean intel_intersect_cliprects( drm_clip_rect_t *dst, @@ -190,6 +192,45 @@ void intelWindowMoved( struct intel_context *intel ) } } + /* Get updated plane info so we sync against the right vblank counter */ + if (intel->intelScreen->driScrnPriv->ddxMinor >= 7) { + drmI830Sarea *sarea = intel->sarea; + drm_clip_rect_t drw_rect = { .x1 = dPriv->x, .x2 = dPriv->x + dPriv->w, + .y1 = dPriv->y, .y2 = dPriv->y + dPriv->h }; + drm_clip_rect_t planeA_rect = { .x1 = sarea->planeA_x, .y1 = sarea->planeA_y, + .x2 = sarea->planeA_x + sarea->planeA_w, + .y2 = sarea->planeA_y + sarea->planeA_h }; + drm_clip_rect_t planeB_rect = { .x1 = sarea->planeB_x, .y1 = sarea->planeB_y, + .x2 = sarea->planeB_x + sarea->planeB_w, + .y2 = sarea->planeB_y + sarea->planeB_h }; + GLint areaA = driIntersectArea( drw_rect, planeA_rect ); + GLint areaB = driIntersectArea( drw_rect, planeB_rect ); + GLuint flags = dPriv->vblFlags; + + /* Update vblank info + */ + if (areaB > areaA || (areaA == areaB && areaB > 0)) { + flags = dPriv->vblFlags | VBLANK_FLAG_SECONDARY; + } else { + flags = dPriv->vblFlags & ~VBLANK_FLAG_SECONDARY; + } + + if (flags != dPriv->vblFlags && dPriv->vblFlags && + !(dPriv->vblFlags & VBLANK_FLAG_NO_IRQ)) { + drmVBlank vbl; + + vbl.request.type = DRM_VBLANK_ABSOLUTE; + + if ( dPriv->vblFlags & VBLANK_FLAG_SECONDARY ) + vbl.request.type |= DRM_VBLANK_SECONDARY; + + dPriv->vblFlags = flags; + driGetCurrentVBlank(dPriv, dPriv->vblFlags, &dPriv->vblSeq); + } + } else { + dPriv->vblFlags &= ~VBLANK_FLAG_SECONDARY; + } + _mesa_resize_framebuffer(&intel->ctx, (GLframebuffer*)dPriv->driverPrivate, dPriv->w, dPriv->h); diff --git a/src/mesa/drivers/dri/i965/intel_context.c b/src/mesa/drivers/dri/i965/intel_context.c index 1fbf571..05a9aec 100644 --- a/src/mesa/drivers/dri/i965/intel_context.c +++ b/src/mesa/drivers/dri/i965/intel_context.c @@ -327,9 +327,10 @@ GLboolean intelInitContext( struct intel_context *intel, GLcontext *ctx = &intel->ctx; GLcontext *shareCtx = (GLcontext *) sharedContextPrivate; __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv; + __DRIdrawablePrivate *dPriv = driContextPriv->driDrawablePriv; intelScreenPrivate *intelScreen = (intelScreenPrivate *)sPriv->private; - volatile drmI830Sarea *saPriv = (volatile drmI830Sarea *) - (((GLubyte *)sPriv->pSAREA)+intelScreen->sarea_priv_offset); + drmI830Sarea *saPriv = (drmI830Sarea *) + (((GLubyte *)sPriv->pSAREA)+intelScreen->sarea_priv_offset); if (!_mesa_initialize_context(&intel->ctx, mesaVis, shareCtx, @@ -347,8 +348,8 @@ GLboolean intelInitContext( struct intel_context *intel, driParseConfigFiles (&intel->optionCache, &intelScreen->optionCache, intel->driScreen->myNum, "i965"); - intel->vblank_flags = (intel->intelScreen->irq_active != 0) - ? driGetDefaultVBlankFlags(&intel->optionCache) : VBLANK_FLAG_NO_IRQ; + dPriv->vblFlags = (intel->intelScreen->irq_active != 0) + ? driGetDefaultVBlankFlags(&intel->optionCache) : VBLANK_FLAG_NO_IRQ; ctx->Const.MaxTextureMaxAnisotropy = 2.0; @@ -582,8 +583,9 @@ GLboolean intelMakeCurrent(__DRIcontextPrivate *driContextPriv, if ( intel->driDrawable != driDrawPriv ) { /* Shouldn't the readbuffer be stored also? */ - driDrawableInitVBlank( driDrawPriv, intel->vblank_flags, - &intel->vbl_seq ); + driDrawableInitVBlank( driDrawPriv, + driDrawPriv->vblFlags, + &driDrawPriv->vblSeq); intel->driDrawable = driDrawPriv; intelWindowMoved( intel ); diff --git a/src/mesa/drivers/dri/i965/intel_context.h b/src/mesa/drivers/dri/i965/intel_context.h index 053d93a..26d6923 100644 --- a/src/mesa/drivers/dri/i965/intel_context.h +++ b/src/mesa/drivers/dri/i965/intel_context.h @@ -237,7 +237,7 @@ struct intel_context __DRIdrawablePrivate *driReadDrawable; __DRIscreenPrivate *driScreen; intelScreenPrivate *intelScreen; - volatile drmI830Sarea *sarea; + drmI830Sarea *sarea; FILE *aub_file; @@ -248,11 +248,6 @@ struct intel_context */ driOptionCache optionCache; - /* VBI - */ - GLuint vbl_seq; - GLuint vblank_flags; - int64_t swap_ust; int64_t swap_missed_ust; diff --git a/src/mesa/drivers/dri/i965/server/i830_common.h b/src/mesa/drivers/dri/i965/server/i830_common.h index f320378..452c400 100644 --- a/src/mesa/drivers/dri/i965/server/i830_common.h +++ b/src/mesa/drivers/dri/i965/server/i830_common.h @@ -119,6 +119,15 @@ typedef struct { unsigned int depth_tiled; unsigned int rotated_tiled; unsigned int rotated2_tiled; + + int planeA_x; + int planeA_y; + int planeA_w; + int planeA_h; + int planeB_x; + int planeB_y; + int planeB_w; + int planeB_h; } drmI830Sarea; /* Flags for perf_boxes