DRI2: initial MSC support

Add support for MSC queries and waits along the same lines as asynchronous
swapbuffers.
This commit is contained in:
Jesse Barnes 2009-09-03 14:23:52 -07:00
parent ecf7439af4
commit 94d2897c95
7 changed files with 437 additions and 73 deletions

View file

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

View file

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

View file

@ -245,7 +245,7 @@ __glXDRIdrawableDestroy(__GLXdrawable *drawable)
}
static GLboolean
__glXDRIdrawableSwapBuffers(__GLXdrawable *basePrivate)
__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *basePrivate)
{
__GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate;
__GLXDRIscreen *screen =

View file

@ -174,18 +174,15 @@ __glXDRIdrawableWaitGL(__GLXdrawable *drawable)
* swap should happen, then perform the copy when we receive it.
*/
static GLboolean
__glXDRIdrawableSwapBuffers(__GLXdrawable *drawable)
__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *drawable)
{
__GLXDRIdrawable *priv = (__GLXDRIdrawable *) drawable;
__GLXDRIscreen *screen = priv->screen;
int interval = 1;
if (screen->swapControl)
interval = screen->swapControl->getSwapInterval(priv->driDrawable);
CARD64 unused;
(*screen->flush->flushInvalidate)(priv->driDrawable);
if (DRI2SwapBuffers(drawable->pDraw, interval) != Success)
if (DRI2SwapBuffers(client, drawable->pDraw, 0, 0, 0, &unused) != Success)
return FALSE;
return TRUE;
@ -194,12 +191,10 @@ __glXDRIdrawableSwapBuffers(__GLXdrawable *drawable)
static int
__glXDRIdrawableSwapInterval(__GLXdrawable *drawable, int interval)
{
__GLXDRIdrawable *draw = (__GLXDRIdrawable *) drawable;
__GLXDRIscreen *screen =
(__GLXDRIscreen *) glxGetScreen(drawable->pDraw->pScreen);
if (interval <= 0) /* || interval > BIGNUM? */
return GLX_BAD_VALUE;
if (screen->swapControl)
screen->swapControl->setSwapInterval(draw->driDrawable, interval);
DRI2SwapInterval(drawable->pDraw, interval);
return 0;
}

View file

@ -34,6 +34,7 @@
#include <xorg-config.h>
#endif
#include <errno.h>
#include <xf86drm.h>
#include "xf86Module.h"
#include "scrnintstr.h"
@ -60,17 +61,75 @@ typedef struct _DRI2Drawable {
unsigned int swapsPending;
unsigned int flipsPending;
ClientPtr blockedClient;
int swap_interval;
CARD64 swap_count;
CARD64 last_swap_target; /* most recently queued swap target */
} DRI2DrawableRec, *DRI2DrawablePtr;
typedef struct _DRI2Screen *DRI2ScreenPtr;
typedef struct _DRI2SwapData *DRI2SwapDataPtr;
typedef struct _DRI2FrameEvent *DRI2FrameEventPtr;
typedef struct _DRI2SwapData {
#define container_of(ptr,type,mem) ((type *)((char *)(ptr) - offsetof(type, \
mem)))
struct list {
struct list *prev, *next;
};
static inline void list_init(struct list *l)
{
l->prev = l;
l->next = l;
}
static inline void __list_add(struct list *l, struct list *prev,
struct list *next)
{
prev->next = l;
l->prev = prev;
l->next = next;
next->prev = l;
}
static inline void list_add(struct list *l, struct list *head)
{
__list_add(l, head, head->next);
}
static inline void list_add_tail(struct list *l, struct list *head)
{
__list_add(l, head->prev, head);
}
static inline void list_del(struct list *l)
{
l->prev->next = l->next;
l->next->prev = l->prev;
list_init(l);
}
static inline Bool list_is_empty(struct list *l)
{
return l->next == l;
}
#define list_foreach_safe(cur, tmp, head) \
for (cur = (head)->next, tmp = cur->next; cur != (head); \
cur = tmp, tmp = cur->next)
enum DRI2FrameEventType {
DRI2_SWAP,
DRI2_WAITMSC,
};
typedef struct _DRI2FrameEvent {
DrawablePtr pDraw;
ScreenPtr pScreen;
ClientPtr client;
enum DRI2FrameEventType type;
int frame;
DRI2SwapDataPtr next;
} DRI2SwapDataRec;
struct list link;
} DRI2FrameEventRec;
typedef struct _DRI2Screen {
const char *driverName;
@ -78,12 +137,15 @@ typedef struct _DRI2Screen {
int fd;
unsigned int lastSequence;
drmEventContext event_context;
DRI2SwapDataPtr swaps; /* Pending swap list */
struct list swaps;
DRI2CreateBufferProcPtr CreateBuffer;
DRI2DestroyBufferProcPtr DestroyBuffer;
DRI2CopyRegionProcPtr CopyRegion;
DRI2SetupSwapProcPtr SetupSwap;
DRI2SwapBuffersProcPtr SwapBuffers;
DRI2GetMSCProcPtr GetMSC;
DRI2SetupWaitMSCProcPtr SetupWaitMSC;
HandleExposuresProcPtr HandleExposures;
} DRI2ScreenRec;
@ -141,6 +203,9 @@ DRI2CreateDrawable(DrawablePtr pDraw)
pPriv->swapsPending = 0;
pPriv->flipsPending = 0;
pPriv->blockedClient = NULL;
pPriv->swap_count = 0;
pPriv->swap_interval = 1;
pPriv->last_swap_target = 0;
if (pDraw->type == DRAWABLE_WINDOW)
{
@ -383,46 +448,66 @@ DRI2FlipCheck(DrawablePtr pDraw)
return TRUE;
}
static Bool DRI2AddSwap(DrawablePtr pDraw, int frame)
static Bool DRI2AddFrameEvent(DrawablePtr pDraw, ClientPtr client,
enum DRI2FrameEventType type, int frame)
{
DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
DRI2DrawablePtr pPriv;
DRI2SwapDataPtr new;
DRI2FrameEventPtr new;
pPriv = DRI2GetDrawable(pDraw);
if (pPriv == NULL)
return FALSE;
new = xcalloc(1, sizeof(DRI2SwapDataRec));
new = xcalloc(1, sizeof(DRI2FrameEventRec));
if (!new)
return FALSE;
new->pScreen = pDraw->pScreen;
new->pDraw = pDraw;
new->client = client;
new->frame = frame;
new->next = ds->swaps;
ds->swaps = new;
new->type = type;
list_add_tail(&new->link, &ds->swaps);
return TRUE;
}
static void DRI2RemoveSwap(DRI2SwapDataPtr swap)
static void DRI2RemoveFrameEvent(DRI2FrameEventPtr event)
{
ScreenPtr pScreen = swap->pScreen;
DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
DRI2SwapDataPtr cur = ds->swaps;
while (cur) {
if (cur == swap) {
cur->next = swap->next;
xfree(swap);
}
cur = cur->next;
}
list_del(&event->link);
xfree(event);
}
static void
DRI2SwapSubmit(DRI2SwapDataPtr swap)
DRI2WaitMSCComplete(DRI2FrameEventPtr swap, unsigned int sequence,
unsigned int tv_sec, unsigned int tv_usec)
{
DrawablePtr pDraw = swap->pDraw;
DRI2DrawablePtr pPriv;
pPriv = DRI2GetDrawable(pDraw);
if (pPriv == NULL)
return;
ProcDRI2WaitMSCReply(swap->client, ((CARD64)tv_sec * 1000000) + tv_usec,
sequence, pPriv->swap_count);
if (pPriv->blockedClient)
AttendClient(pPriv->blockedClient);
pPriv->blockedClient = NULL;
}
/* Wake up clients waiting for flip/swap completion */
static void DRI2SwapComplete(DRI2DrawablePtr pPriv)
{
pPriv->swap_count++;
}
static void
DRI2SwapSubmit(DRI2FrameEventPtr swap)
{
DrawablePtr pDraw = swap->pDraw;
ScreenPtr pScreen = swap->pScreen;
@ -472,8 +557,7 @@ DRI2SwapSubmit(DRI2SwapDataPtr swap)
box.y2 = pPriv->height;
REGION_INIT(pScreen, &region, &box, 0);
DRI2CopyRegion(pDraw, &region,
DRI2BufferFrontLeft, DRI2BufferBackLeft);
DRI2CopyRegion(pDraw, &region, DRI2BufferFrontLeft, DRI2BufferBackLeft);
pPriv->swapsPending--;
DRI2SwapComplete(pPriv);
@ -483,14 +567,39 @@ static void drm_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, void *user_data)
{
DRI2ScreenPtr ds = user_data;
DRI2SwapDataPtr cur = ds->swaps;
DRI2DrawablePtr pPriv;
struct list *cur, *tmp;
while (cur) {
if (cur->frame == frame) {
DRI2SwapSubmit(cur);
DRI2RemoveSwap(cur);
if (list_is_empty(&ds->swaps)) {
ErrorF("tried to dequeue non-existent swap\n");
return;
}
list_foreach_safe(cur, tmp, &ds->swaps) {
DRI2FrameEventPtr swap = container_of(cur, DRI2FrameEventRec, link);
if (swap->frame != frame)
continue;
pPriv = DRI2GetDrawable(swap->pDraw);
if (pPriv == NULL) {
DRI2RemoveFrameEvent(swap);
ErrorF("no dri2priv??\n");
continue; /* FIXME: check priv refcounting */
}
cur = cur->next;
switch (swap->type) {
case DRI2_SWAP:
DRI2SwapSubmit(swap);
break;
case DRI2_WAITMSC:
DRI2WaitMSCComplete(swap, frame, tv_sec, tv_usec);
break;
default:
/* Unknown type */
break;
}
DRI2RemoveFrameEvent(swap);
}
}
@ -505,17 +614,24 @@ drm_wakeup_handler(pointer data, int err, pointer p)
}
int
DRI2SwapBuffers(DrawablePtr pDraw, int interval)
DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
CARD64 divisor, CARD64 remainder, CARD64 *swap_target)
{
DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
DRI2DrawablePtr pPriv;
drmVBlank vbl;
CARD64 event_frame;
int ret;
pPriv = DRI2GetDrawable(pDraw);
if (pPriv == NULL)
return BadDrawable;
vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
/*
* 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;
if (DRI2FlipCheck(pDraw)) {
/*
@ -523,25 +639,28 @@ DRI2SwapBuffers(DrawablePtr pDraw, int interval)
* frame - 1 to honor the swap interval.
*/
pPriv->flipsPending++;
if (interval > 1) {
vbl.request.sequence = interval - 1;
if (pPriv->swap_interval > 1) {
*swap_target = *swap_target - 1;
/* fixme: prevent cliprect changes between now and the flip */
} else {
/* FIXME: perform immediate page flip */
DRI2SwapComplete(pPriv);
return Success;
return 0;
}
} else {
pPriv->swapsPending++;
vbl.request.sequence = interval;
}
/* fixme: get correct crtc for this drawable */
drmWaitVBlank(ds->fd, &vbl);
ret = (*ds->SetupSwap)(pDraw, *swap_target, divisor, remainder, ds,
&event_frame);
if (!ret)
return BadDrawable;
/* Request an event for the requested frame */
if (!DRI2AddSwap(pDraw, vbl.reply.sequence))
if (!DRI2AddFrameEvent(pDraw, client, DRI2_SWAP, event_frame))
return BadValue;
pPriv->last_swap_target = *swap_target;
return Success;
}
@ -565,15 +684,88 @@ DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable)
return FALSE;
}
/* Wake up clients waiting for flip/swap completion */
void DRI2SwapComplete(void *data)
void
DRI2SwapInterval(DrawablePtr pDrawable, int interval)
{
DRI2DrawablePtr pPriv = data;
DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
if (pPriv->blockedClient)
AttendClient(pPriv->blockedClient);
/* fixme: check against arbitrary max? */
pPriv->blockedClient = NULL;
pPriv->swap_interval = interval;
}
int
DRI2GetMSC(DrawablePtr pDraw, CARD64 *ust, CARD64 *msc, CARD64 *sbc)
{
DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
DRI2DrawablePtr pPriv;
Bool ret;
pPriv = DRI2GetDrawable(pDraw);
if (pPriv == NULL)
return BadDrawable;
if (!ds->GetMSC)
FatalError("advertised MSC support w/o driver hook\n");
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;
CARD64 event_frame;
Bool ret;
pPriv = DRI2GetDrawable(pDraw);
if (pPriv == NULL)
return BadDrawable;
ret = (*ds->SetupWaitMSC)(pDraw, target_msc, divisor, remainder, ds,
&event_frame);
if (!ret) {
ErrorF("setupmsc failed: %d\n", ret);
return BadDrawable;
}
ret = DRI2AddFrameEvent(pDraw, client, DRI2_WAITMSC, event_frame);
if (!ret)
return BadDrawable;
/* DDX returned > 0, block the client until its wait completes */
if (pPriv->blockedClient == NULL) {
IgnoreClient(client);
pPriv->blockedClient = client;
}
return Success;
}
int
DRI2WaitSBC(DrawablePtr pDraw, CARD64 target_sbc, CARD64 *ust, CARD64 *msc,
CARD64 *sbc)
{
DRI2DrawablePtr pPriv;
pPriv = DRI2GetDrawable(pDraw);
if (pPriv == NULL)
return BadDrawable;
/* fixme: put client to sleep until swap count hits target */
return Success;
}
void
@ -675,12 +867,18 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
ds->DestroyBuffer = info->DestroyBuffer;
ds->CopyRegion = info->CopyRegion;
if (info->version >= 4)
if (info->version >= 4) {
ds->SetupSwap = info->SetupSwap;
ds->SwapBuffers = info->SwapBuffers;
ds->SetupWaitMSC = info->SetupWaitMSC;
ds->GetMSC = info->GetMSC;
}
ds->event_context.version = DRM_EVENT_CONTEXT_VERSION;
ds->event_context.vblank_handler = drm_vblank_handler;
list_init(&ds->swaps);
AddGeneralSocket(ds->fd);
RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
drm_wakeup_handler, ds);

View file

@ -58,6 +58,12 @@ typedef void (*DRI2CopyRegionProcPtr)(DrawablePtr pDraw,
RegionPtr pRegion,
DRI2BufferPtr pDestBuffer,
DRI2BufferPtr pSrcBuffer);
typedef int (*DRI2SetupSwapProcPtr)(DrawablePtr pDraw,
CARD64 target_msc,
CARD64 divisor,
CARD64 remainder,
void *data,
CARD64 *event_frame);
typedef Bool (*DRI2SwapBuffersProcPtr)(ScreenPtr pScreen,
DRI2BufferPtr pFrontBuffer,
DRI2BufferPtr pBackBuffer,
@ -71,6 +77,14 @@ typedef DRI2BufferPtr (*DRI2CreateBufferProcPtr)(DrawablePtr pDraw,
unsigned int format);
typedef void (*DRI2DestroyBufferProcPtr)(DrawablePtr pDraw,
DRI2BufferPtr buffer);
typedef int (*DRI2GetMSCProcPtr)(DrawablePtr pDraw, CARD64 *ust,
CARD64 *msc);
typedef int (*DRI2SetupWaitMSCProcPtr)(DrawablePtr pDraw,
CARD64 target_msc,
CARD64 divisor,
CARD64 remainder,
void *data,
CARD64 *event_frame);
/**
* Version of the DRI2InfoRec structure defined in this header
@ -86,8 +100,10 @@ typedef struct {
DRI2CreateBufferProcPtr CreateBuffer;
DRI2DestroyBufferProcPtr DestroyBuffer;
DRI2CopyRegionProcPtr CopyRegion;
DRI2SetupSwapProcPtr SetupSwap;
DRI2SwapBuffersProcPtr SwapBuffers;
DRI2GetMSCProcPtr GetMSC;
DRI2SetupWaitMSCProcPtr SetupWaitMSC;
} DRI2InfoRec, *DRI2InfoPtr;
extern _X_EXPORT Bool DRI2ScreenInit(ScreenPtr pScreen,
@ -141,8 +157,23 @@ extern _X_EXPORT DRI2BufferPtr *DRI2GetBuffersWithFormat(DrawablePtr pDraw,
int *width, int *height, unsigned int *attachments, int count,
int *out_count);
extern _X_EXPORT int DRI2SwapBuffers(DrawablePtr pDrawable, int interval);
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);
extern _X_EXPORT Bool DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable);
extern _X_EXPORT void DRI2SwapComplete(void *data);
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(DrawablePtr pDraw, CARD64 target_sbc,
CARD64 *ust, CARD64 *msc, CARD64 *sbc);
#define DRI2_WAITMSC_ERROR -1
#define DRI2_WAITMSC_DONE 0
#define DRI2_WAITMSC_BLOCK 1
#endif

View file

@ -259,9 +259,6 @@ ProcDRI2GetBuffers(ClientPtr client)
&pDrawable, &status))
return status;
if (DRI2WaitSwap(client, pDrawable))
return client->noClientException;
attachments = (unsigned int *) &stuff[1];
buffers = DRI2GetBuffers(pDrawable, &width, &height,
attachments, stuff->count, &count);
@ -286,9 +283,6 @@ ProcDRI2GetBuffersWithFormat(ClientPtr client)
&pDrawable, &status))
return status;
if (DRI2WaitSwap(client, pDrawable))
return client->noClientException;
attachments = (unsigned int *) &stuff[1];
buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
attachments, stuff->count, &count);
@ -335,11 +329,26 @@ 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);
@ -347,7 +356,132 @@ ProcDRI2SwapBuffers(ClientPtr client)
if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
return status;
return DRI2SwapBuffers(pDrawable, 0); /* get swap interval... */
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);
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, &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, &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
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, &pDrawable, &status))
return status;
target = vals_to_card64(stuff->target_sbc_lo, stuff->target_sbc_hi);
status = DRI2WaitSBC(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
@ -380,6 +514,12 @@ ProcDRI2Dispatch (ClientPtr client)
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);
default:
return BadRequest;
}