DRI2: add support for new DRI2 protocol requests
Support the new DRI2 2.2 protocol requests: DRI2SwapBuffers, DRI2GetMSC, DRI2WaitMSC, DRI2WaitSBC and DRI2SwapInterval. These requests allow the server to support the SGI_video_sync, SGI_swap_interval, and OML_sync_control GLX extensions if DDX support is present. The new DDX APIs are documented in dri2.h. Reviewed-by: Kristian Høgsberg <krh@bitplanet.net> Reviewed-by: Adam Jackson <ajax@nwnk.net> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
This commit is contained in:
		
							parent
							
								
									e10072b7c7
								
							
						
					
					
						commit
						04a54f69a8
					
				|  | @ -750,7 +750,7 @@ RECORDPROTO="recordproto >= 1.13.99.1" | |||
| SCRNSAVERPROTO="scrnsaverproto >= 1.1" | ||||
| RESOURCEPROTO="resourceproto" | ||||
| DRIPROTO="xf86driproto >= 2.1.0" | ||||
| DRI2PROTO="dri2proto >= 2.1" | ||||
| DRI2PROTO="dri2proto >= 2.2" | ||||
| XINERAMAPROTO="xineramaproto" | ||||
| BIGFONTPROTO="xf86bigfontproto >= 1.2.0" | ||||
| XCALIBRATEPROTO="xcalibrateproto" | ||||
|  |  | |||
|  | @ -1481,7 +1481,7 @@ int __glXDisp_SwapBuffers(__GLXclientState *cl, GLbyte *pc) | |||
| 	return error; | ||||
| 
 | ||||
|     if (pGlxDraw->type == DRAWABLE_WINDOW && | ||||
| 	(*pGlxDraw->swapBuffers)(pGlxDraw) == GL_FALSE) | ||||
| 	(*pGlxDraw->swapBuffers)(cl->client, pGlxDraw) == GL_FALSE) | ||||
| 	return __glXError(GLXBadDrawable); | ||||
| 
 | ||||
|     return Success; | ||||
|  |  | |||
|  | @ -55,6 +55,10 @@ struct __GLXcontext { | |||
| 				     unsigned long mask); | ||||
|     int            (*forceCurrent)  (__GLXcontext *context); | ||||
| 
 | ||||
|     Bool           (*wait)          (__GLXcontext *context, | ||||
| 				     __GLXclientState *cl, | ||||
| 				     int *error); | ||||
| 
 | ||||
|     __GLXtextureFromPixmap *textureFromPixmap; | ||||
| 
 | ||||
|     /*
 | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ enum { | |||
| 
 | ||||
| struct __GLXdrawable { | ||||
|     void (*destroy)(__GLXdrawable *private); | ||||
|     GLboolean (*swapBuffers)(__GLXdrawable *); | ||||
|     GLboolean (*swapBuffers)(ClientPtr client, __GLXdrawable *); | ||||
|     void      (*copySubBuffer)(__GLXdrawable *drawable, | ||||
| 			       int x, int y, int w, int h); | ||||
|     void      (*waitX)(__GLXdrawable *); | ||||
|  |  | |||
|  | @ -245,7 +245,7 @@ __glXDRIdrawableDestroy(__GLXdrawable *drawable) | |||
| } | ||||
| 
 | ||||
| static GLboolean | ||||
| __glXDRIdrawableSwapBuffers(__GLXdrawable *basePrivate) | ||||
| __glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *basePrivate) | ||||
| { | ||||
|     __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate; | ||||
|     __GLXDRIscreen *screen = | ||||
|  |  | |||
|  | @ -70,6 +70,7 @@ struct __GLXDRIscreen { | |||
| 
 | ||||
|     const __DRIcoreExtension *core; | ||||
|     const __DRIdri2Extension *dri2; | ||||
|     const __DRI2flushExtension *flush; | ||||
|     const __DRIcopySubBufferExtension *copySubBuffer; | ||||
|     const __DRIswapControlExtension *swapControl; | ||||
|     const __DRItexBufferExtension *texBuffer; | ||||
|  | @ -132,17 +133,6 @@ __glXDRIdrawableCopySubBuffer(__GLXdrawable *drawable, | |||
| 		   DRI2BufferFrontLeft, DRI2BufferBackLeft); | ||||
| } | ||||
| 
 | ||||
| static GLboolean | ||||
| __glXDRIdrawableSwapBuffers(__GLXdrawable *drawable) | ||||
| { | ||||
|     __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; | ||||
| 
 | ||||
|     __glXDRIdrawableCopySubBuffer(drawable, 0, 0, | ||||
| 				  private->width, private->height); | ||||
| 
 | ||||
|     return TRUE; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| __glXDRIdrawableWaitX(__GLXdrawable *drawable) | ||||
| { | ||||
|  | @ -177,9 +167,37 @@ __glXDRIdrawableWaitGL(__GLXdrawable *drawable) | |||
| 		   DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Copy or flip back to front, honoring the swap interval if possible. | ||||
|  * | ||||
|  * If the kernel supports it, we request an event for the frame when the | ||||
|  * swap should happen, then perform the copy when we receive it. | ||||
|  */ | ||||
| static GLboolean | ||||
| __glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *drawable) | ||||
| { | ||||
|     __GLXDRIdrawable *priv = (__GLXDRIdrawable *) drawable; | ||||
|     __GLXDRIscreen *screen = priv->screen; | ||||
|     CARD64 unused; | ||||
| 
 | ||||
|     if (screen->flush) | ||||
| 	(*screen->flush->flushInvalidate)(priv->driDrawable); | ||||
| 
 | ||||
|     if (DRI2SwapBuffers(client, drawable->pDraw, 0, 0, 0, &unused, | ||||
| 			NULL, drawable->pDraw) != Success) | ||||
| 	return FALSE; | ||||
| 
 | ||||
|     return TRUE; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| __glXDRIdrawableSwapInterval(__GLXdrawable *drawable, int interval) | ||||
| { | ||||
|     if (interval <= 0) /* || interval > BIGNUM? */ | ||||
| 	return GLX_BAD_VALUE; | ||||
| 
 | ||||
|     DRI2SwapInterval(drawable->pDraw, interval); | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -241,6 +259,18 @@ __glXDRIcontextForceCurrent(__GLXcontext *baseContext) | |||
| 					read->driDrawable); | ||||
| } | ||||
| 
 | ||||
| static Bool | ||||
| __glXDRIcontextWait(__GLXcontext *baseContext, | ||||
| 		    __GLXclientState *cl, int *error) | ||||
| { | ||||
|     if (DRI2WaitSwap(cl->client, baseContext->drawPriv->pDraw)) { | ||||
| 	*error = cl->client->noClientException; | ||||
| 	return TRUE; | ||||
|     } | ||||
| 
 | ||||
|     return FALSE; | ||||
| } | ||||
| 
 | ||||
| #ifdef __DRI_TEX_BUFFER | ||||
| 
 | ||||
| static int | ||||
|  | @ -346,6 +376,7 @@ __glXDRIscreenCreateContext(__GLXscreen *baseScreen, | |||
|     context->base.copy              = __glXDRIcontextCopy; | ||||
|     context->base.forceCurrent      = __glXDRIcontextForceCurrent; | ||||
|     context->base.textureFromPixmap = &__glXDRItextureFromPixmap; | ||||
|     context->base.wait              = __glXDRIcontextWait; | ||||
| 
 | ||||
|     context->driContext = | ||||
| 	(*screen->dri2->createNewContext)(screen->driScreen, | ||||
|  | @ -581,6 +612,14 @@ initializeExtensions(__GLXDRIscreen *screen) | |||
| 	    LogMessage(X_INFO, "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n"); | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| #ifdef __DRI2_FLUSH | ||||
| 	if (strcmp(extensions[i]->name, __DRI2_FLUSH) == 0 && | ||||
| 	    extensions[i]->version >= __DRI2_FLUSH_VERSION) { | ||||
| 		screen->flush = (__DRI2flushExtension *) extensions[i]; | ||||
| 	} | ||||
| #endif | ||||
| 
 | ||||
| 	/* Ignore unknown extensions */ | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -108,7 +108,7 @@ __glXDRIdrawableDestroy(__GLXdrawable *drawable) | |||
| } | ||||
| 
 | ||||
| static GLboolean | ||||
| __glXDRIdrawableSwapBuffers(__GLXdrawable *drawable) | ||||
| __glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *drawable) | ||||
| { | ||||
|     __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; | ||||
|     const __DRIcoreExtension *core = private->screen->core; | ||||
|  |  | |||
|  | @ -446,6 +446,9 @@ __GLXcontext *__glXForceCurrent(__GLXclientState *cl, GLXContextTag tag, | |||
|     	} | ||||
|     } | ||||
|      | ||||
|     if (cx->wait && (*cx->wait)(cx, cl, error)) | ||||
| 	return NULL; | ||||
| 
 | ||||
|     if (cx == __glXLastContext) { | ||||
| 	/* No need to re-bind */ | ||||
| 	return cx; | ||||
|  |  | |||
|  | @ -56,7 +56,14 @@ | |||
| #include <GL/gl.h> | ||||
| #include <GL/glxproto.h> | ||||
| 
 | ||||
| /* For glxscreens.h */ | ||||
| /*
 | ||||
| ** GLX resources. | ||||
| */ | ||||
| typedef XID GLXContextID; | ||||
| typedef XID GLXPixmap; | ||||
| typedef XID GLXDrawable; | ||||
| 
 | ||||
| typedef struct __GLXclientStateRec __GLXclientState; | ||||
| typedef struct __GLXdrawable __GLXdrawable; | ||||
| typedef struct __GLXcontext __GLXcontext; | ||||
| 
 | ||||
|  | @ -71,15 +78,6 @@ typedef struct __GLXcontext __GLXcontext; | |||
| #define False 0 | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
| ** GLX resources. | ||||
| */ | ||||
| typedef XID GLXContextID; | ||||
| typedef XID GLXPixmap; | ||||
| typedef XID GLXDrawable; | ||||
| 
 | ||||
| typedef struct __GLXclientStateRec __GLXclientState; | ||||
| 
 | ||||
| extern __GLXscreen *glxGetScreen(ScreenPtr pScreen); | ||||
| extern __GLXclientState *glxGetClient(ClientPtr pClient); | ||||
| 
 | ||||
|  |  | |||
|  | @ -53,8 +53,6 @@ int DoSwapInterval(__GLXclientState *cl, GLbyte *pc, int do_swap) | |||
| 
 | ||||
|     cx = __glXLookupContextByTag(cl, tag); | ||||
| 
 | ||||
|     LogMessage(X_ERROR, "%s: cx = %p, GLX screen = %p\n", __func__, | ||||
| 	       cx, (cx == NULL) ? NULL : cx->pGlxScreen); | ||||
|     if ((cx == NULL) || (cx->pGlxScreen == NULL)) { | ||||
| 	client->errorValue = tag; | ||||
| 	return __glXError(GLXBadContext); | ||||
|  | @ -68,7 +66,7 @@ int DoSwapInterval(__GLXclientState *cl, GLbyte *pc, int do_swap) | |||
| 
 | ||||
|     if (cx->drawPriv == NULL) { | ||||
| 	client->errorValue = tag; | ||||
| 	return __glXError(GLXBadDrawable); | ||||
| 	return BadValue; | ||||
|     } | ||||
|      | ||||
|     pc += __GLX_VENDPRIV_HDR_SIZE; | ||||
|  | @ -76,6 +74,9 @@ int DoSwapInterval(__GLXclientState *cl, GLbyte *pc, int do_swap) | |||
|       ? bswap_32(*(int *)(pc + 0)) | ||||
|       :          *(int *)(pc + 0); | ||||
| 
 | ||||
|     if (interval <= 0) | ||||
| 	return BadValue; | ||||
| 
 | ||||
|     (void) (*cx->pGlxScreen->swapInterval)(cx->drawPriv, interval); | ||||
|     return Success; | ||||
| } | ||||
|  |  | |||
|  | @ -34,10 +34,12 @@ | |||
| #include <xorg-config.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <errno.h> | ||||
| #include <xf86drm.h> | ||||
| #include "xf86Module.h" | ||||
| #include "scrnintstr.h" | ||||
| #include "windowstr.h" | ||||
| #include "dixstruct.h" | ||||
| #include "dri2.h" | ||||
| #include "xf86VGAarbiter.h" | ||||
| 
 | ||||
|  | @ -56,9 +58,17 @@ typedef struct _DRI2Drawable { | |||
|     int			 height; | ||||
|     DRI2BufferPtr	*buffers; | ||||
|     int			 bufferCount; | ||||
|     unsigned int	 pendingSequence; | ||||
|     unsigned int	 swapsPending; | ||||
|     ClientPtr		 blockedClient; | ||||
|     int			 swap_interval; | ||||
|     CARD64		 swap_count; | ||||
|     CARD64		 target_sbc; /* -1 means no SBC wait outstanding */ | ||||
|     CARD64		 last_swap_target; /* most recently queued swap target */ | ||||
|     int			 swap_limit; /* for N-buffering */ | ||||
| } DRI2DrawableRec, *DRI2DrawablePtr; | ||||
| 
 | ||||
| typedef struct _DRI2Screen *DRI2ScreenPtr; | ||||
| 
 | ||||
| typedef struct _DRI2Screen { | ||||
|     const char			*driverName; | ||||
|     const char			*deviceName; | ||||
|  | @ -68,9 +78,12 @@ typedef struct _DRI2Screen { | |||
|     DRI2CreateBufferProcPtr	 CreateBuffer; | ||||
|     DRI2DestroyBufferProcPtr	 DestroyBuffer; | ||||
|     DRI2CopyRegionProcPtr	 CopyRegion; | ||||
|     DRI2ScheduleSwapProcPtr	 ScheduleSwap; | ||||
|     DRI2GetMSCProcPtr		 GetMSC; | ||||
|     DRI2ScheduleWaitMSCProcPtr	 ScheduleWaitMSC; | ||||
| 
 | ||||
|     HandleExposuresProcPtr       HandleExposures; | ||||
| } DRI2ScreenRec, *DRI2ScreenPtr; | ||||
| } DRI2ScreenRec; | ||||
| 
 | ||||
| static DRI2ScreenPtr | ||||
| DRI2GetScreen(ScreenPtr pScreen) | ||||
|  | @ -84,6 +97,9 @@ DRI2GetDrawable(DrawablePtr pDraw) | |||
|     WindowPtr		  pWin; | ||||
|     PixmapPtr		  pPixmap; | ||||
| 
 | ||||
|     if (!pDraw) | ||||
| 	return NULL; | ||||
| 
 | ||||
|     if (pDraw->type == DRAWABLE_WINDOW) | ||||
|     { | ||||
| 	pWin = (WindowPtr) pDraw; | ||||
|  | @ -119,6 +135,13 @@ DRI2CreateDrawable(DrawablePtr pDraw) | |||
|     pPriv->height = pDraw->height; | ||||
|     pPriv->buffers = NULL; | ||||
|     pPriv->bufferCount = 0; | ||||
|     pPriv->swapsPending = 0; | ||||
|     pPriv->blockedClient = NULL; | ||||
|     pPriv->swap_count = 0; | ||||
|     pPriv->target_sbc = -1; | ||||
|     pPriv->swap_interval = 1; | ||||
|     pPriv->last_swap_target = -1; | ||||
|     pPriv->swap_limit = 1; /* default to double buffering */ | ||||
| 
 | ||||
|     if (pDraw->type == DRAWABLE_WINDOW) | ||||
|     { | ||||
|  | @ -308,6 +331,50 @@ DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height, | |||
| 			  out_count, TRUE); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * In the direct rendered case, we throttle the clients that have more | ||||
|  * than their share of outstanding swaps (and thus busy buffers) when a | ||||
|  * new GetBuffers request is received.  In the AIGLX case, we allow the | ||||
|  * client to get the new buffers, but throttle when the next GLX request | ||||
|  * comes in (see __glXDRIcontextWait()). | ||||
|  */ | ||||
| Bool | ||||
| DRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw) | ||||
| { | ||||
|     DRI2DrawablePtr pPriv; | ||||
| 
 | ||||
|     pPriv = DRI2GetDrawable(pDraw); | ||||
|     if (pPriv == NULL) | ||||
| 	return FALSE; | ||||
| 
 | ||||
|     /* Throttle to swap limit */ | ||||
|     if ((pPriv->swapsPending >= pPriv->swap_limit) && | ||||
| 	!pPriv->blockedClient) { | ||||
| 	ResetCurrentRequest(client); | ||||
| 	client->sequence--; | ||||
| 	IgnoreClient(client); | ||||
| 	pPriv->blockedClient = client; | ||||
| 	return TRUE; | ||||
|     } | ||||
| 
 | ||||
|     return FALSE; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| DRI2BlockClient(ClientPtr client, DrawablePtr pDraw) | ||||
| { | ||||
|     DRI2DrawablePtr pPriv; | ||||
| 
 | ||||
|     pPriv = DRI2GetDrawable(pDraw); | ||||
|     if (pPriv == NULL) | ||||
| 	return; | ||||
| 
 | ||||
|     if (pPriv->blockedClient == NULL) { | ||||
| 	IgnoreClient(client); | ||||
| 	pPriv->blockedClient = client; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int | ||||
| DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, | ||||
| 	       unsigned int dest, unsigned int src) | ||||
|  | @ -338,6 +405,324 @@ DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, | |||
|     return Success; | ||||
| } | ||||
| 
 | ||||
| /* Can this drawable be page flipped? */ | ||||
| Bool | ||||
| DRI2CanFlip(DrawablePtr pDraw) | ||||
| { | ||||
|     ScreenPtr pScreen = pDraw->pScreen; | ||||
|     WindowPtr pWin, pRoot; | ||||
|     PixmapPtr pWinPixmap, pRootPixmap; | ||||
| 
 | ||||
|     if (pDraw->type == DRAWABLE_PIXMAP) | ||||
| 	return TRUE; | ||||
| 
 | ||||
|     pRoot = WindowTable[pScreen->myNum]; | ||||
|     pRootPixmap = pScreen->GetWindowPixmap(pRoot); | ||||
| 
 | ||||
|     pWin = (WindowPtr) pDraw; | ||||
|     pWinPixmap = pScreen->GetWindowPixmap(pWin); | ||||
|     if (pRootPixmap != pWinPixmap) | ||||
| 	return FALSE; | ||||
|     if (!REGION_EQUAL(pScreen, &pWin->clipList, &pRoot->winSize)) | ||||
| 	return FALSE; | ||||
| 
 | ||||
|     return TRUE; | ||||
| } | ||||
| 
 | ||||
| /* Can we do a pixmap exchange instead of a blit? */ | ||||
| Bool | ||||
| DRI2CanExchange(DrawablePtr pDraw) | ||||
| { | ||||
|     return FALSE; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame, | ||||
| 		    unsigned int tv_sec, unsigned int tv_usec) | ||||
| { | ||||
|     DRI2DrawablePtr pPriv; | ||||
| 
 | ||||
|     pPriv = DRI2GetDrawable(pDraw); | ||||
|     if (pPriv == NULL) | ||||
| 	return; | ||||
| 
 | ||||
|     ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec, | ||||
| 			 frame, pPriv->swap_count); | ||||
| 
 | ||||
|     if (pPriv->blockedClient) | ||||
| 	AttendClient(pPriv->blockedClient); | ||||
| 
 | ||||
|     pPriv->blockedClient = NULL; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| DRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame, | ||||
| 	       unsigned int tv_sec, unsigned int tv_usec) | ||||
| { | ||||
|     ScreenPtr	    pScreen = pDraw->pScreen; | ||||
|     DRI2DrawablePtr pPriv; | ||||
| 
 | ||||
|     pPriv = DRI2GetDrawable(pDraw); | ||||
|     if (pPriv == NULL) { | ||||
|         xf86DrvMsg(pScreen->myNum, X_ERROR, | ||||
| 		   "[DRI2] %s: bad drawable\n", __func__); | ||||
| 	return; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|      * Swap completed.  Either wake up an SBC waiter or a client that was | ||||
|      * blocked due to GLX activity during a swap. | ||||
|      */ | ||||
|     if (pPriv->target_sbc != -1 && | ||||
| 	pPriv->target_sbc >= pPriv->swap_count) { | ||||
| 	ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec, | ||||
| 			     frame, pPriv->swap_count); | ||||
| 	pPriv->target_sbc = -1; | ||||
| 
 | ||||
| 	AttendClient(pPriv->blockedClient); | ||||
| 	pPriv->blockedClient = NULL; | ||||
|     } else if (pPriv->target_sbc == -1) { | ||||
| 	if (pPriv->blockedClient) | ||||
| 	    AttendClient(pPriv->blockedClient); | ||||
| 	pPriv->blockedClient = NULL; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void | ||||
| DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame, | ||||
| 		   unsigned int tv_sec, unsigned int tv_usec, int type, | ||||
| 		   DRI2SwapEventPtr swap_complete, void *swap_data) | ||||
| { | ||||
|     ScreenPtr	    pScreen = pDraw->pScreen; | ||||
|     DRI2DrawablePtr pPriv; | ||||
|     CARD64          ust = 0; | ||||
| 
 | ||||
|     pPriv = DRI2GetDrawable(pDraw); | ||||
|     if (pPriv == NULL) { | ||||
|         xf86DrvMsg(pScreen->myNum, X_ERROR, | ||||
| 		   "[DRI2] %s: bad drawable\n", __func__); | ||||
| 	return; | ||||
|     } | ||||
| 
 | ||||
|     if (pPriv->refCount == 0) { | ||||
|         xf86DrvMsg(pScreen->myNum, X_ERROR, | ||||
| 		   "[DRI2] %s: bad drawable refcount\n", __func__); | ||||
| 	xfree(pPriv); | ||||
| 	return; | ||||
|     } | ||||
| 
 | ||||
|     ust = ((CARD64)tv_sec * 1000000) + tv_usec; | ||||
|     if (swap_complete) | ||||
| 	swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count); | ||||
| 
 | ||||
|     pPriv->swapsPending--; | ||||
|     pPriv->swap_count++; | ||||
| 
 | ||||
|     DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec); | ||||
| } | ||||
| 
 | ||||
| Bool | ||||
| DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable) | ||||
| { | ||||
|     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); | ||||
| 
 | ||||
|     /* If we're currently waiting for a swap on this drawable, reset
 | ||||
|      * the request and suspend the client.  We only support one | ||||
|      * blocked client per drawable. */ | ||||
|     if ((pPriv->swapsPending) && | ||||
| 	pPriv->blockedClient == NULL) { | ||||
| 	ResetCurrentRequest(client); | ||||
| 	client->sequence--; | ||||
| 	DRI2BlockClient(client, pDrawable); | ||||
| 	return TRUE; | ||||
|     } | ||||
| 
 | ||||
|     return FALSE; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, | ||||
| 		CARD64 divisor, CARD64 remainder, CARD64 *swap_target, | ||||
| 		DRI2SwapEventPtr func, void *data) | ||||
| { | ||||
|     ScreenPtr       pScreen = pDraw->pScreen; | ||||
|     DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen); | ||||
|     DRI2DrawablePtr pPriv; | ||||
|     DRI2BufferPtr   pDestBuffer = NULL, pSrcBuffer = NULL; | ||||
|     CARD64          ust; | ||||
|     int             ret, i; | ||||
| 
 | ||||
|     pPriv = DRI2GetDrawable(pDraw); | ||||
|     if (pPriv == NULL) { | ||||
|         xf86DrvMsg(pScreen->myNum, X_ERROR, | ||||
| 		   "[DRI2] %s: bad drawable\n", __func__); | ||||
| 	return BadDrawable; | ||||
|     } | ||||
| 
 | ||||
|     for (i = 0; i < pPriv->bufferCount; i++) { | ||||
| 	if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft) | ||||
| 	    pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i]; | ||||
| 	if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft) | ||||
| 	    pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i]; | ||||
|     } | ||||
|     if (pSrcBuffer == NULL || pDestBuffer == NULL) { | ||||
|         xf86DrvMsg(pScreen->myNum, X_ERROR, | ||||
| 		   "[DRI2] %s: drawable has no back or front?\n", __func__); | ||||
| 	return BadDrawable; | ||||
|     } | ||||
| 
 | ||||
|     /* Old DDX, just blit */ | ||||
|     if (!ds->ScheduleSwap) { | ||||
| 	BoxRec box; | ||||
| 	RegionRec region; | ||||
| 
 | ||||
| 	box.x1 = 0; | ||||
| 	box.y1 = 0; | ||||
| 	box.x2 = pDraw->width; | ||||
| 	box.y2 = pDraw->height; | ||||
| 	REGION_INIT(pScreen, ®ion, &box, 0); | ||||
| 
 | ||||
| 	pPriv->swapsPending++; | ||||
| 
 | ||||
| 	(*ds->CopyRegion)(pDraw, ®ion, pDestBuffer, pSrcBuffer); | ||||
| 	DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE, | ||||
| 			 func, data); | ||||
| 	return Success; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|      * In the simple glXSwapBuffers case, all params will be 0, and we just | ||||
|      * need to schedule a swap for the last swap target + the swap interval. | ||||
|      * If the last swap target hasn't been set yet, call into the driver | ||||
|      * to get the current count. | ||||
|      */ | ||||
|     if (target_msc == 0 && divisor == 0 && remainder == 0 && | ||||
| 	pPriv->last_swap_target < 0) { | ||||
| 	ret = (*ds->GetMSC)(pDraw, &ust, &target_msc); | ||||
| 	if (!ret) { | ||||
| 	    xf86DrvMsg(pScreen->myNum, X_ERROR, | ||||
| 		       "[DRI2] %s: driver failed to return current MSC\n", | ||||
| 		       __func__); | ||||
| 	    return BadDrawable; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|     /* First swap needs to initialize last_swap_target */ | ||||
|     if (pPriv->last_swap_target < 0) | ||||
| 	pPriv->last_swap_target = target_msc; | ||||
| 
 | ||||
|     /*
 | ||||
|      * Swap target for this swap is last swap target + swap interval since | ||||
|      * we have to account for the current swap count, interval, and the | ||||
|      * number of pending swaps. | ||||
|      */ | ||||
|     *swap_target = pPriv->last_swap_target + pPriv->swap_interval; | ||||
| 
 | ||||
|     ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer, | ||||
| 			      swap_target, divisor, remainder, func, data); | ||||
|     if (!ret) { | ||||
|         xf86DrvMsg(pScreen->myNum, X_ERROR, | ||||
| 		   "[DRI2] %s: driver failed to schedule swap\n", __func__); | ||||
| 	return BadDrawable; | ||||
|     } | ||||
| 
 | ||||
|     pPriv->swapsPending++; | ||||
|     pPriv->last_swap_target = *swap_target; | ||||
| 
 | ||||
|     return Success; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| DRI2SwapInterval(DrawablePtr pDrawable, int interval) | ||||
| { | ||||
|     DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); | ||||
| 
 | ||||
|     /* fixme: check against arbitrary max? */ | ||||
| 
 | ||||
|     pPriv->swap_interval = interval; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| DRI2GetMSC(DrawablePtr pDraw, CARD64 *ust, CARD64 *msc, CARD64 *sbc) | ||||
| { | ||||
|     ScreenPtr pScreen = pDraw->pScreen; | ||||
|     DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); | ||||
|     DRI2DrawablePtr pPriv; | ||||
|     Bool ret; | ||||
| 
 | ||||
|     pPriv = DRI2GetDrawable(pDraw); | ||||
|     if (pPriv == NULL) { | ||||
|         xf86DrvMsg(pScreen->myNum, X_ERROR, | ||||
| 		   "[DRI2] %s: bad drawable\n", __func__); | ||||
| 	return BadDrawable; | ||||
|     } | ||||
| 
 | ||||
|     if (!ds->GetMSC) { | ||||
| 	*ust = 0; | ||||
| 	*msc = 0; | ||||
| 	*sbc = pPriv->swap_count; | ||||
| 	return Success; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|      * Spec needs to be updated to include unmapped or redirected | ||||
|      * drawables | ||||
|      */ | ||||
| 
 | ||||
|     ret = (*ds->GetMSC)(pDraw, ust, msc); | ||||
|     if (!ret) | ||||
| 	return BadDrawable; | ||||
| 
 | ||||
|     *sbc = pPriv->swap_count; | ||||
| 
 | ||||
|     return Success; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| DRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc, | ||||
| 	    CARD64 divisor, CARD64 remainder) | ||||
| { | ||||
|     DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); | ||||
|     DRI2DrawablePtr pPriv; | ||||
|     Bool ret; | ||||
| 
 | ||||
|     pPriv = DRI2GetDrawable(pDraw); | ||||
|     if (pPriv == NULL) | ||||
| 	return BadDrawable; | ||||
| 
 | ||||
|     /* Old DDX just completes immediately */ | ||||
|     if (!ds->ScheduleWaitMSC) { | ||||
| 	DRI2WaitMSCComplete(client, pDraw, target_msc, 0, 0); | ||||
| 
 | ||||
| 	return Success; | ||||
|     } | ||||
| 
 | ||||
|     ret = (*ds->ScheduleWaitMSC)(client, pDraw, target_msc, divisor, remainder); | ||||
|     if (!ret) | ||||
| 	return BadDrawable; | ||||
| 
 | ||||
|     return Success; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc, | ||||
| 	    CARD64 *ust, CARD64 *msc, CARD64 *sbc) | ||||
| { | ||||
|     DRI2DrawablePtr pPriv; | ||||
| 
 | ||||
|     pPriv = DRI2GetDrawable(pDraw); | ||||
|     if (pPriv == NULL) | ||||
| 	return BadDrawable; | ||||
| 
 | ||||
|     if (pPriv->swap_count >= target_sbc) | ||||
| 	return Success; | ||||
| 
 | ||||
|     pPriv->target_sbc = target_sbc; | ||||
|     DRI2BlockClient(client, pDraw); | ||||
| 
 | ||||
|     return Success; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| DRI2DestroyDrawable(DrawablePtr pDraw) | ||||
| { | ||||
|  | @ -363,7 +748,11 @@ DRI2DestroyDrawable(DrawablePtr pDraw) | |||
| 	xfree(pPriv->buffers); | ||||
|     } | ||||
| 
 | ||||
|     xfree(pPriv); | ||||
|     /* If the window is destroyed while we have a swap pending, don't
 | ||||
|      * actually free the priv yet.  We'll need it in the DRI2SwapComplete() | ||||
|      * callback and we'll free it there once we're done. */ | ||||
|     if (!pPriv->swapsPending) | ||||
| 	xfree(pPriv); | ||||
| 
 | ||||
|     if (pDraw->type == DRAWABLE_WINDOW) | ||||
|     { | ||||
|  | @ -421,7 +810,7 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) | |||
|         return FALSE; | ||||
|     } | ||||
| 
 | ||||
|     ds = xalloc(sizeof *ds); | ||||
|     ds = xcalloc(1, sizeof *ds); | ||||
|     if (!ds) | ||||
| 	return FALSE; | ||||
| 
 | ||||
|  | @ -433,6 +822,12 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info) | |||
|     ds->DestroyBuffer  = info->DestroyBuffer; | ||||
|     ds->CopyRegion     = info->CopyRegion; | ||||
| 
 | ||||
|     if (info->version >= 4) { | ||||
| 	ds->ScheduleSwap = info->ScheduleSwap; | ||||
| 	ds->ScheduleWaitMSC = info->ScheduleWaitMSC; | ||||
| 	ds->GetMSC = info->GetMSC; | ||||
|     } | ||||
| 
 | ||||
|     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds); | ||||
| 
 | ||||
|     xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n"); | ||||
|  |  | |||
|  | @ -47,6 +47,9 @@ typedef struct { | |||
| } DRI2BufferRec, *DRI2BufferPtr; | ||||
| 
 | ||||
| typedef DRI2BufferRec DRI2Buffer2Rec, *DRI2Buffer2Ptr; | ||||
| typedef void (*DRI2SwapEventPtr)(ClientPtr client, void *data, int type, | ||||
| 				 CARD64 ust, CARD64 msc, CARD64 sbc); | ||||
| 
 | ||||
| 
 | ||||
| typedef DRI2BufferPtr	(*DRI2CreateBuffersProcPtr)(DrawablePtr pDraw, | ||||
| 						    unsigned int *attachments, | ||||
|  | @ -58,20 +61,98 @@ typedef void		(*DRI2CopyRegionProcPtr)(DrawablePtr pDraw, | |||
| 						 RegionPtr pRegion, | ||||
| 						 DRI2BufferPtr pDestBuffer, | ||||
| 						 DRI2BufferPtr pSrcBuffer); | ||||
| 
 | ||||
| typedef void		(*DRI2WaitProcPtr)(WindowPtr pWin, | ||||
| 					   unsigned int sequence); | ||||
| 
 | ||||
| /**
 | ||||
|  * Schedule a buffer swap | ||||
|  * | ||||
|  * This callback is used to support glXSwapBuffers and the OML_sync_control | ||||
|  * extension (see it for a description of the params). | ||||
|  * | ||||
|  * Drivers should queue an event for the frame count that satisfies the | ||||
|  * parameters passed in.  If the event is in the future (i.e. the conditions | ||||
|  * aren't currently satisfied), the server may block the client at the next | ||||
|  * GLX request using DRI2WaitSwap. When the event arrives, drivers should call | ||||
|  * \c DRI2SwapComplete, which will handle waking the client and returning | ||||
|  * the appropriate data. | ||||
|  * | ||||
|  * The DDX is responsible for doing a flip, exchange, or blit of the swap | ||||
|  * when the corresponding event arrives.  The \c DRI2CanFlip and | ||||
|  * \c DRI2CanExchange functions can be used as helpers for this purpose. | ||||
|  * | ||||
|  * \param client client pointer (used for block/unblock) | ||||
|  * \param pDraw drawable whose count we want | ||||
|  * \param pDestBuffer current front buffer | ||||
|  * \param pSrcBuffer current back buffer | ||||
|  * \param target_msc frame count to wait for | ||||
|  * \param divisor divisor for condition equation | ||||
|  * \param remainder remainder for division equation | ||||
|  * \param func function to call when the swap completes | ||||
|  * \param data data for the callback \p func. | ||||
|  */ | ||||
| typedef int		(*DRI2ScheduleSwapProcPtr)(ClientPtr client, | ||||
| 						   DrawablePtr pDraw, | ||||
| 						   DRI2BufferPtr pDestBuffer, | ||||
| 						   DRI2BufferPtr pSrcBuffer, | ||||
| 						   CARD64 *target_msc, | ||||
| 						   CARD64 divisor, | ||||
| 						   CARD64 remainder, | ||||
| 						   DRI2SwapEventPtr func, | ||||
| 						   void *data); | ||||
| typedef DRI2BufferPtr	(*DRI2CreateBufferProcPtr)(DrawablePtr pDraw, | ||||
| 						   unsigned int attachment, | ||||
| 						   unsigned int format); | ||||
| typedef void		(*DRI2DestroyBufferProcPtr)(DrawablePtr pDraw, | ||||
| 						    DRI2BufferPtr buffer); | ||||
| 
 | ||||
| /**
 | ||||
|  * Get current media stamp counter values | ||||
|  * | ||||
|  * This callback is used to support the SGI_video_sync and OML_sync_control | ||||
|  * extensions. | ||||
|  * | ||||
|  * Drivers should return the current frame counter and the timestamp from | ||||
|  * when the returned frame count was last incremented. | ||||
|  * | ||||
|  * The count should correspond to the screen where the drawable is currently | ||||
|  * visible.  If the drawable isn't visible (e.g. redirected), the server | ||||
|  * should return BadDrawable to the client, pending GLX spec updates to | ||||
|  * define this behavior. | ||||
|  * | ||||
|  * \param pDraw drawable whose count we want | ||||
|  * \param ust timestamp from when the count was last incremented. | ||||
|  * \param mst current frame count | ||||
|  */ | ||||
| typedef int		(*DRI2GetMSCProcPtr)(DrawablePtr pDraw, CARD64 *ust, | ||||
| 					     CARD64 *msc); | ||||
| /**
 | ||||
|  * Schedule a frame count related wait | ||||
|  * | ||||
|  * This callback is used to support the SGI_video_sync and OML_sync_control | ||||
|  * extensions.  See those specifications for details on how to handle | ||||
|  * the divisor and remainder parameters. | ||||
|  * | ||||
|  * Drivers should queue an event for the frame count that satisfies the | ||||
|  * parameters passed in.  If the event is in the future (i.e. the conditions | ||||
|  * aren't currently satisfied), the driver should block the client using | ||||
|  * \c DRI2BlockClient.  When the event arrives, drivers should call | ||||
|  * \c DRI2WaitMSCComplete, which will handle waking the client and returning | ||||
|  * the appropriate data. | ||||
|  * | ||||
|  * \param client client pointer (used for block/unblock) | ||||
|  * \param pDraw drawable whose count we want | ||||
|  * \param target_msc frame count to wait for | ||||
|  * \param divisor divisor for condition equation | ||||
|  * \param remainder remainder for division equation | ||||
|  */ | ||||
| typedef int		(*DRI2ScheduleWaitMSCProcPtr)(ClientPtr client, | ||||
| 						      DrawablePtr pDraw, | ||||
| 						      CARD64 target_msc, | ||||
| 						      CARD64 divisor, | ||||
| 						      CARD64 remainder); | ||||
| /**
 | ||||
|  * Version of the DRI2InfoRec structure defined in this header | ||||
|  */ | ||||
| #define DRI2INFOREC_VERSION 3 | ||||
| #define DRI2INFOREC_VERSION 4 | ||||
| 
 | ||||
| typedef struct { | ||||
|     unsigned int version;	/**< Version of this struct */ | ||||
|  | @ -83,7 +164,9 @@ typedef struct { | |||
|     DRI2DestroyBufferProcPtr	DestroyBuffer; | ||||
|     DRI2CopyRegionProcPtr	CopyRegion; | ||||
|     DRI2WaitProcPtr		Wait; | ||||
| 
 | ||||
|     DRI2ScheduleSwapProcPtr	ScheduleSwap; | ||||
|     DRI2GetMSCProcPtr		GetMSC; | ||||
|     DRI2ScheduleWaitMSCProcPtr	ScheduleWaitMSC; | ||||
| }  DRI2InfoRec, *DRI2InfoPtr; | ||||
| 
 | ||||
| extern _X_EXPORT Bool DRI2ScreenInit(ScreenPtr	pScreen, | ||||
|  | @ -137,4 +220,38 @@ extern _X_EXPORT DRI2BufferPtr *DRI2GetBuffersWithFormat(DrawablePtr pDraw, | |||
| 	int *width, int *height, unsigned int *attachments, int count, | ||||
| 	int *out_count); | ||||
| 
 | ||||
| extern _X_EXPORT void DRI2SwapInterval(DrawablePtr pDrawable, int interval); | ||||
| extern _X_EXPORT int DRI2SwapBuffers(ClientPtr client, DrawablePtr pDrawable, | ||||
| 				     CARD64 target_msc, CARD64 divisor, | ||||
| 				     CARD64 remainder, CARD64 *swap_target, | ||||
| 				     DRI2SwapEventPtr func, void *data); | ||||
| extern _X_EXPORT Bool DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable); | ||||
| 
 | ||||
| extern _X_EXPORT int DRI2GetMSC(DrawablePtr pDrawable, CARD64 *ust, | ||||
| 				CARD64 *msc, CARD64 *sbc); | ||||
| extern _X_EXPORT int DRI2WaitMSC(ClientPtr client, DrawablePtr pDrawable, | ||||
| 				 CARD64 target_msc, CARD64 divisor, | ||||
| 				 CARD64 remainder); | ||||
| extern _X_EXPORT int ProcDRI2WaitMSCReply(ClientPtr client, CARD64 ust, | ||||
| 					  CARD64 msc, CARD64 sbc); | ||||
| extern _X_EXPORT int DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, | ||||
| 				 CARD64 target_sbc, CARD64 *ust, CARD64 *msc, | ||||
| 				 CARD64 *sbc); | ||||
| extern _X_EXPORT Bool DRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw); | ||||
| 
 | ||||
| extern _X_EXPORT Bool DRI2CanFlip(DrawablePtr pDraw); | ||||
| 
 | ||||
| extern _X_EXPORT Bool DRI2CanExchange(DrawablePtr pDraw); | ||||
| 
 | ||||
| extern _X_EXPORT void DRI2BlockClient(ClientPtr client, DrawablePtr pDraw); | ||||
| 
 | ||||
| extern _X_EXPORT void DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, | ||||
| 				       int frame, unsigned int tv_sec, | ||||
| 				       unsigned int tv_usec, int type, | ||||
| 				       DRI2SwapEventPtr swap_complete, | ||||
| 				       void *swap_data); | ||||
| extern _X_EXPORT void DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, | ||||
| 					  int frame, unsigned int tv_sec, | ||||
| 					  unsigned int tv_usec); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -259,6 +259,9 @@ ProcDRI2GetBuffers(ClientPtr client) | |||
| 		       &pDrawable, &status)) | ||||
| 	return status; | ||||
| 
 | ||||
|     if (DRI2ThrottleClient(client, pDrawable)) | ||||
| 	return client->noClientException; | ||||
| 
 | ||||
|     attachments = (unsigned int *) &stuff[1]; | ||||
|     buffers = DRI2GetBuffers(pDrawable, &width, &height, | ||||
| 			     attachments, stuff->count, &count); | ||||
|  | @ -283,6 +286,9 @@ ProcDRI2GetBuffersWithFormat(ClientPtr client) | |||
| 		       &pDrawable, &status)) | ||||
| 	return status; | ||||
| 
 | ||||
|     if (DRI2ThrottleClient(client, pDrawable)) | ||||
| 	return client->noClientException; | ||||
| 
 | ||||
|     attachments = (unsigned int *) &stuff[1]; | ||||
|     buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height, | ||||
| 				       attachments, stuff->count, &count); | ||||
|  | @ -329,6 +335,185 @@ ProcDRI2CopyRegion(ClientPtr client) | |||
|     return client->noClientException; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| load_swap_reply(xDRI2SwapBuffersReply *rep, CARD64 sbc) | ||||
| { | ||||
|     rep->swap_hi = sbc >> 32; | ||||
|     rep->swap_lo = sbc & 0xffffffff; | ||||
| } | ||||
| 
 | ||||
| static CARD64 | ||||
| vals_to_card64(CARD32 lo, CARD32 hi) | ||||
| { | ||||
|     return (CARD64)hi << 32 | lo; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| ProcDRI2SwapBuffers(ClientPtr client) | ||||
| { | ||||
|     REQUEST(xDRI2SwapBuffersReq); | ||||
|     xDRI2SwapBuffersReply rep; | ||||
|     DrawablePtr pDrawable; | ||||
|     CARD64 target_msc, divisor, remainder, swap_target; | ||||
|     int status; | ||||
| 
 | ||||
|     REQUEST_SIZE_MATCH(xDRI2SwapBuffersReq); | ||||
| 
 | ||||
|     if (!validDrawable(client, stuff->drawable, | ||||
| 		       DixReadAccess | DixWriteAccess, &pDrawable, &status)) | ||||
| 	return status; | ||||
| 
 | ||||
|     target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi); | ||||
|     divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi); | ||||
|     remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi); | ||||
| 
 | ||||
|     status = DRI2SwapBuffers(client, pDrawable, target_msc, divisor, remainder, | ||||
| 			     &swap_target, NULL, pDrawable); | ||||
|     if (status != Success) | ||||
| 	return BadDrawable; | ||||
| 
 | ||||
|     rep.type = X_Reply; | ||||
|     rep.length = 0; | ||||
|     rep.sequenceNumber = client->sequence; | ||||
|     load_swap_reply(&rep, swap_target); | ||||
| 
 | ||||
|     WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep); | ||||
| 
 | ||||
|     return client->noClientException; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| load_msc_reply(xDRI2MSCReply *rep, CARD64 ust, CARD64 msc, CARD64 sbc) | ||||
| { | ||||
|     rep->ust_hi = ust >> 32; | ||||
|     rep->ust_lo = ust & 0xffffffff; | ||||
|     rep->msc_hi = msc >> 32; | ||||
|     rep->msc_lo = msc & 0xffffffff; | ||||
|     rep->sbc_hi = sbc >> 32; | ||||
|     rep->sbc_lo = sbc & 0xffffffff; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| ProcDRI2GetMSC(ClientPtr client) | ||||
| { | ||||
|     REQUEST(xDRI2GetMSCReq); | ||||
|     xDRI2MSCReply rep; | ||||
|     DrawablePtr pDrawable; | ||||
|     CARD64 ust, msc, sbc; | ||||
|     int status; | ||||
| 
 | ||||
|     REQUEST_SIZE_MATCH(xDRI2GetMSCReq); | ||||
| 
 | ||||
|     if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable, | ||||
| 		       &status)) | ||||
| 	return status; | ||||
| 
 | ||||
|     status = DRI2GetMSC(pDrawable, &ust, &msc, &sbc); | ||||
|     if (status != Success) | ||||
| 	return status; | ||||
| 
 | ||||
|     rep.type = X_Reply; | ||||
|     rep.length = 0; | ||||
|     rep.sequenceNumber = client->sequence; | ||||
|     load_msc_reply(&rep, ust, msc, sbc); | ||||
| 
 | ||||
|     WriteToClient(client, sizeof(xDRI2MSCReply), &rep); | ||||
| 
 | ||||
|     return client->noClientException; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| ProcDRI2WaitMSC(ClientPtr client) | ||||
| { | ||||
|     REQUEST(xDRI2WaitMSCReq); | ||||
|     DrawablePtr pDrawable; | ||||
|     CARD64 target, divisor, remainder; | ||||
|     int status; | ||||
| 
 | ||||
|     /* FIXME: in restart case, client may be gone at this point */ | ||||
| 
 | ||||
|     REQUEST_SIZE_MATCH(xDRI2WaitMSCReq); | ||||
| 
 | ||||
|     if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable, | ||||
| 		       &status)) | ||||
| 	return status; | ||||
| 
 | ||||
|     target = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi); | ||||
|     divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi); | ||||
|     remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi); | ||||
| 
 | ||||
|     status = DRI2WaitMSC(client, pDrawable, target, divisor, remainder); | ||||
|     if (status != Success) | ||||
| 	return status; | ||||
| 
 | ||||
|     return client->noClientException; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| ProcDRI2WaitMSCReply(ClientPtr client, CARD64 ust, CARD64 msc, CARD64 sbc) | ||||
| { | ||||
|     xDRI2MSCReply rep; | ||||
| 
 | ||||
|     rep.type = X_Reply; | ||||
|     rep.length = 0; | ||||
|     rep.sequenceNumber = client->sequence; | ||||
|     load_msc_reply(&rep, ust, msc, sbc); | ||||
| 
 | ||||
|     WriteToClient(client, sizeof(xDRI2MSCReply), &rep); | ||||
| 
 | ||||
|     return client->noClientException; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| ProcDRI2SwapInterval(ClientPtr client) | ||||
| { | ||||
|     REQUEST(xDRI2SwapIntervalReq); | ||||
|     DrawablePtr pDrawable; | ||||
|     int status; | ||||
| 
 | ||||
|     /* FIXME: in restart case, client may be gone at this point */ | ||||
| 
 | ||||
|     REQUEST_SIZE_MATCH(xDRI2SwapIntervalReq); | ||||
| 
 | ||||
|     if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess, | ||||
| 		       &pDrawable, &status)) | ||||
| 	return status; | ||||
| 
 | ||||
|     DRI2SwapInterval(pDrawable, stuff->interval); | ||||
| 
 | ||||
|     return client->noClientException; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| ProcDRI2WaitSBC(ClientPtr client) | ||||
| { | ||||
|     REQUEST(xDRI2WaitSBCReq); | ||||
|     xDRI2MSCReply rep; | ||||
|     DrawablePtr pDrawable; | ||||
|     CARD64 target, ust, msc, sbc; | ||||
|     int status; | ||||
| 
 | ||||
|     REQUEST_SIZE_MATCH(xDRI2WaitSBCReq); | ||||
| 
 | ||||
|     if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable, | ||||
| 		       &status)) | ||||
| 	return status; | ||||
| 
 | ||||
|     target = vals_to_card64(stuff->target_sbc_lo, stuff->target_sbc_hi); | ||||
|     status = DRI2WaitSBC(client, pDrawable, target, &ust, &msc, &sbc); | ||||
|     if (status != Success) | ||||
| 	return status; | ||||
| 
 | ||||
|     rep.type = X_Reply; | ||||
|     rep.length = 0; | ||||
|     rep.sequenceNumber = client->sequence; | ||||
|     load_msc_reply(&rep, ust, msc, sbc); | ||||
| 
 | ||||
|     WriteToClient(client, sizeof(xDRI2MSCReply), &rep); | ||||
| 
 | ||||
|     return client->noClientException; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| ProcDRI2Dispatch (ClientPtr client) | ||||
| { | ||||
|  | @ -357,6 +542,16 @@ ProcDRI2Dispatch (ClientPtr client) | |||
| 	return ProcDRI2CopyRegion(client); | ||||
|     case X_DRI2GetBuffersWithFormat: | ||||
| 	return ProcDRI2GetBuffersWithFormat(client); | ||||
|     case X_DRI2SwapBuffers: | ||||
| 	return ProcDRI2SwapBuffers(client); | ||||
|     case X_DRI2GetMSC: | ||||
| 	return ProcDRI2GetMSC(client); | ||||
|     case X_DRI2WaitMSC: | ||||
| 	return ProcDRI2WaitMSC(client); | ||||
|     case X_DRI2WaitSBC: | ||||
| 	return ProcDRI2WaitSBC(client); | ||||
|     case X_DRI2SwapInterval: | ||||
| 	return ProcDRI2SwapInterval(client); | ||||
|     default: | ||||
| 	return BadRequest; | ||||
|     } | ||||
|  |  | |||
|  | @ -53,7 +53,7 @@ | |||
| 
 | ||||
| /* DRI2 */ | ||||
| #define SERVER_DRI2_MAJOR_VERSION		1 | ||||
| #define SERVER_DRI2_MINOR_VERSION		1 | ||||
| #define SERVER_DRI2_MINOR_VERSION		2 | ||||
| 
 | ||||
| /* Generic event extension */ | ||||
| #define SERVER_GE_MAJOR_VERSION                 1 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue