Merge remote branch 'jbarnes/master'

This commit is contained in:
Keith Packard 2010-04-06 12:36:15 -07:00
commit a7698a6776
5 changed files with 143 additions and 75 deletions

View File

@ -616,6 +616,7 @@ glxDRILeaveVT (int index, int flags)
static void static void
initializeExtensions(__GLXDRIscreen *screen) initializeExtensions(__GLXDRIscreen *screen)
{ {
ScreenPtr pScreen = screen->base.pScreen;
const __DRIextension **extensions; const __DRIextension **extensions;
int i; int i;
@ -625,10 +626,17 @@ initializeExtensions(__GLXDRIscreen *screen)
"GLX_MESA_copy_sub_buffer"); "GLX_MESA_copy_sub_buffer");
LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n");
/* FIXME: only if DDX supports it */
__glXEnableExtension(screen->glx_enable_bits, "GLX_INTEL_swap_event"); __glXEnableExtension(screen->glx_enable_bits, "GLX_INTEL_swap_event");
LogMessage(X_INFO, "AIGLX: enabled GLX_INTEL_swap_event\n"); LogMessage(X_INFO, "AIGLX: enabled GLX_INTEL_swap_event\n");
if (DRI2HasSwapControl(pScreen)) {
__glXEnableExtension(screen->glx_enable_bits,
"GLX_SGI_swap_control");
__glXEnableExtension(screen->glx_enable_bits,
"GLX_MESA_swap_control");
LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n");
}
for (i = 0; extensions[i]; i++) { for (i = 0; extensions[i]; i++) {
#ifdef __DRI_READ_DRAWABLE #ifdef __DRI_READ_DRAWABLE
if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) { if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
@ -639,19 +647,6 @@ initializeExtensions(__GLXDRIscreen *screen)
} }
#endif #endif
#ifdef __DRI_SWAP_CONTROL
if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
screen->swapControl =
(const __DRIswapControlExtension *) extensions[i];
__glXEnableExtension(screen->glx_enable_bits,
"GLX_SGI_swap_control");
__glXEnableExtension(screen->glx_enable_bits,
"GLX_MESA_swap_control");
LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n");
}
#endif
#ifdef __DRI_TEX_BUFFER #ifdef __DRI_TEX_BUFFER
if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) { if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) {
screen->texBuffer = screen->texBuffer =

View File

@ -45,6 +45,9 @@
#include "xf86.h" #include "xf86.h"
CARD8 dri2_major; /* version of DRI2 supported by DDX */
CARD8 dri2_minor;
static int dri2ScreenPrivateKeyIndex; static int dri2ScreenPrivateKeyIndex;
static DevPrivateKey dri2ScreenPrivateKey = &dri2ScreenPrivateKeyIndex; static DevPrivateKey dri2ScreenPrivateKey = &dri2ScreenPrivateKeyIndex;
static int dri2WindowPrivateKeyIndex; static int dri2WindowPrivateKeyIndex;
@ -60,10 +63,13 @@ typedef struct _DRI2Drawable {
int bufferCount; int bufferCount;
unsigned int swapsPending; unsigned int swapsPending;
ClientPtr blockedClient; ClientPtr blockedClient;
Bool blockedOnMsc;
int swap_interval; int swap_interval;
CARD64 swap_count; CARD64 swap_count;
CARD64 target_sbc; /* -1 means no SBC wait outstanding */ int64_t target_sbc; /* -1 means no SBC wait outstanding */
CARD64 last_swap_target; /* most recently queued swap target */ CARD64 last_swap_target; /* most recently queued swap target */
CARD64 last_swap_msc; /* msc at completion of most recent swap */
CARD64 last_swap_ust; /* ust at completion of most recent swap */
int swap_limit; /* for N-buffering */ int swap_limit; /* for N-buffering */
} DRI2DrawableRec, *DRI2DrawablePtr; } DRI2DrawableRec, *DRI2DrawablePtr;
@ -116,9 +122,11 @@ DRI2GetDrawable(DrawablePtr pDraw)
int int
DRI2CreateDrawable(DrawablePtr pDraw) DRI2CreateDrawable(DrawablePtr pDraw)
{ {
DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
WindowPtr pWin; WindowPtr pWin;
PixmapPtr pPixmap; PixmapPtr pPixmap;
DRI2DrawablePtr pPriv; DRI2DrawablePtr pPriv;
CARD64 ust;
pPriv = DRI2GetDrawable(pDraw); pPriv = DRI2GetDrawable(pDraw);
if (pPriv != NULL) if (pPriv != NULL)
@ -138,11 +146,17 @@ DRI2CreateDrawable(DrawablePtr pDraw)
pPriv->bufferCount = 0; pPriv->bufferCount = 0;
pPriv->swapsPending = 0; pPriv->swapsPending = 0;
pPriv->blockedClient = NULL; pPriv->blockedClient = NULL;
pPriv->blockedOnMsc = FALSE;
pPriv->swap_count = 0; pPriv->swap_count = 0;
pPriv->target_sbc = -1; pPriv->target_sbc = -1;
pPriv->swap_interval = 1; pPriv->swap_interval = 1;
pPriv->last_swap_target = -1; /* Initialize last swap target from DDX if possible */
if (!ds->GetMSC || !(*ds->GetMSC)(pDraw, &ust, &pPriv->last_swap_target))
pPriv->last_swap_target = 0;
pPriv->swap_limit = 1; /* default to double buffering */ pPriv->swap_limit = 1; /* default to double buffering */
pPriv->last_swap_msc = 0;
pPriv->last_swap_ust = 0;
if (pDraw->type == DRAWABLE_WINDOW) if (pDraw->type == DRAWABLE_WINDOW)
{ {
@ -390,6 +404,15 @@ DRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw)
return FALSE; return FALSE;
} }
static void
__DRI2BlockClient(ClientPtr client, DRI2DrawablePtr pPriv)
{
if (pPriv->blockedClient == NULL) {
IgnoreClient(client);
pPriv->blockedClient = client;
}
}
void void
DRI2BlockClient(ClientPtr client, DrawablePtr pDraw) DRI2BlockClient(ClientPtr client, DrawablePtr pDraw)
{ {
@ -399,10 +422,8 @@ DRI2BlockClient(ClientPtr client, DrawablePtr pDraw)
if (pPriv == NULL) if (pPriv == NULL)
return; return;
if (pPriv->blockedClient == NULL) { __DRI2BlockClient(client, pPriv);
IgnoreClient(client); pPriv->blockedOnMsc = TRUE;
pPriv->blockedClient = client;
}
} }
int int
@ -483,6 +504,11 @@ DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame,
AttendClient(pPriv->blockedClient); AttendClient(pPriv->blockedClient);
pPriv->blockedClient = NULL; pPriv->blockedClient = NULL;
pPriv->blockedOnMsc = FALSE;
/* If there's still a swap pending, let DRI2SwapComplete free it */
if (pPriv->refCount == 0 && pPriv->swapsPending == 0)
DRI2FreeDrawable(pDraw);
} }
static void static void
@ -500,21 +526,26 @@ DRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame,
} }
/* /*
* Swap completed. Either wake up an SBC waiter or a client that was * Swap completed.
* blocked due to GLX activity during a swap. * Wake the client iff:
* - it was waiting on SBC
* - was blocked due to GLX make current
* - was blocked due to swap throttling
* - is not blocked due to an MSC wait
*/ */
if (pPriv->target_sbc != -1 && if (pPriv->target_sbc != -1 &&
pPriv->target_sbc >= pPriv->swap_count) { pPriv->target_sbc <= pPriv->swap_count) {
ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec, ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec,
frame, pPriv->swap_count); frame, pPriv->swap_count);
pPriv->target_sbc = -1; pPriv->target_sbc = -1;
AttendClient(pPriv->blockedClient); AttendClient(pPriv->blockedClient);
pPriv->blockedClient = NULL; pPriv->blockedClient = NULL;
} else if (pPriv->target_sbc == -1) { } else if (pPriv->target_sbc == -1 && !pPriv->blockedOnMsc) {
if (pPriv->blockedClient) if (pPriv->blockedClient) {
AttendClient(pPriv->blockedClient); AttendClient(pPriv->blockedClient);
pPriv->blockedClient = NULL; pPriv->blockedClient = NULL;
}
} }
} }
@ -534,21 +565,24 @@ DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame,
return; return;
} }
if (pPriv->refCount == 0) { pPriv->swapsPending--;
xf86DrvMsg(pScreen->myNum, X_ERROR, pPriv->swap_count++;
"[DRI2] %s: bad drawable refcount\n", __func__);
DRI2FreeDrawable(pDraw);
return;
}
ust = ((CARD64)tv_sec * 1000000) + tv_usec; ust = ((CARD64)tv_sec * 1000000) + tv_usec;
if (swap_complete) if (swap_complete)
swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count); swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count);
pPriv->swapsPending--; pPriv->last_swap_msc = frame;
pPriv->swap_count++; pPriv->last_swap_ust = ust;
DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec); DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec);
/*
* It's normal for the app to have exited with a swap outstanding, but
* don't free the drawable until they're all complete.
*/
if (pPriv->swapsPending == 0 && pPriv->refCount == 0)
DRI2FreeDrawable(pDraw);
} }
Bool Bool
@ -563,7 +597,7 @@ DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable)
pPriv->blockedClient == NULL) { pPriv->blockedClient == NULL) {
ResetCurrentRequest(client); ResetCurrentRequest(client);
client->sequence--; client->sequence--;
DRI2BlockClient(client, pDrawable); __DRI2BlockClient(client, pPriv);
return TRUE; return TRUE;
} }
@ -579,7 +613,6 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen); DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
DRI2DrawablePtr pPriv; DRI2DrawablePtr pPriv;
DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL; DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL;
CARD64 ust;
int ret, i; int ret, i;
pPriv = DRI2GetDrawable(pDraw); pPriv = DRI2GetDrawable(pDraw);
@ -601,8 +634,8 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
return BadDrawable; return BadDrawable;
} }
/* Old DDX, just blit */ /* Old DDX or no swap interval, just blit */
if (!ds->ScheduleSwap) { if (!ds->ScheduleSwap || !pPriv->swap_interval) {
BoxRec box; BoxRec box;
RegionRec region; RegionRec region;
@ -623,52 +656,52 @@ DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
/* /*
* In the simple glXSwapBuffers case, all params will be 0, and we just * 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. * 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 && if (target_msc == 0 && divisor == 0 && remainder == 0) {
pPriv->last_swap_target < 0) { /*
ret = (*ds->GetMSC)(pDraw, &ust, &target_msc); * Swap target for this swap is last swap target + swap interval since
if (!ret) { * we have to account for the current swap count, interval, and the
xf86DrvMsg(pScreen->myNum, X_ERROR, * number of pending swaps.
"[DRI2] %s: driver failed to return current MSC\n", */
__func__); *swap_target = pPriv->last_swap_target + pPriv->swap_interval;
return BadDrawable; } else {
} /* glXSwapBuffersMscOML could have a 0 target_msc, honor it */
*swap_target = target_msc;
} }
/* First swap needs to initialize last_swap_target */ pPriv->swapsPending++;
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, ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer,
swap_target, divisor, remainder, func, data); swap_target, divisor, remainder, func, data);
if (!ret) { if (!ret) {
pPriv->swapsPending--; /* didn't schedule */
xf86DrvMsg(pScreen->myNum, X_ERROR, xf86DrvMsg(pScreen->myNum, X_ERROR,
"[DRI2] %s: driver failed to schedule swap\n", __func__); "[DRI2] %s: driver failed to schedule swap\n", __func__);
return BadDrawable; return BadDrawable;
} }
pPriv->swapsPending++;
pPriv->last_swap_target = *swap_target; pPriv->last_swap_target = *swap_target;
/* According to spec, return expected swapbuffers count SBC after this swap
* will complete.
*/
*swap_target = pPriv->swap_count + pPriv->swapsPending;
return Success; return Success;
} }
void void
DRI2SwapInterval(DrawablePtr pDrawable, int interval) DRI2SwapInterval(DrawablePtr pDrawable, int interval)
{ {
ScreenPtr pScreen = pDrawable->pScreen;
DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable); DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
/* fixme: check against arbitrary max? */ if (pPriv == NULL) {
xf86DrvMsg(pScreen->myNum, X_ERROR,
"[DRI2] %s: bad drawable\n", __func__);
return;
}
/* fixme: check against arbitrary max? */
pPriv->swap_interval = interval; pPriv->swap_interval = interval;
} }
@ -717,7 +750,7 @@ DRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
Bool ret; Bool ret;
pPriv = DRI2GetDrawable(pDraw); pPriv = DRI2GetDrawable(pDraw);
if (pPriv == NULL) if (pPriv == NULL || pPriv->refCount == 0)
return BadDrawable; return BadDrawable;
/* Old DDX just completes immediately */ /* Old DDX just completes immediately */
@ -741,14 +774,28 @@ DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc,
DRI2DrawablePtr pPriv; DRI2DrawablePtr pPriv;
pPriv = DRI2GetDrawable(pDraw); pPriv = DRI2GetDrawable(pDraw);
if (pPriv == NULL) if (pPriv == NULL || pPriv->refCount == 0)
return BadDrawable; return BadDrawable;
if (pPriv->swap_count >= target_sbc) /* target_sbc == 0 means to block until all pending swaps are
return Success; * finished. Recalculate target_sbc to get that behaviour.
*/
if (target_sbc == 0)
target_sbc = pPriv->swap_count + pPriv->swapsPending;
/* If current swap count already >= target_sbc,
* return immediately with (ust, msc, sbc) triplet of
* most recent completed swap.
*/
if (pPriv->swap_count >= target_sbc) {
*sbc = pPriv->swap_count;
*msc = pPriv->last_swap_msc;
*ust = pPriv->last_swap_ust;
return Success;
}
pPriv->target_sbc = target_sbc; pPriv->target_sbc = target_sbc;
DRI2BlockClient(client, pDraw); __DRI2BlockClient(client, pPriv);
return Success; return Success;
} }
@ -776,13 +823,21 @@ DRI2DestroyDrawable(DrawablePtr pDraw)
xfree(pPriv->buffers); xfree(pPriv->buffers);
} }
/* If the window is destroyed while we have a swap pending, don't /* If the window is destroyed while we have a swap or wait pending, don't
* actually free the priv yet. We'll need it in the DRI2SwapComplete() * actually free the priv yet. We'll need it in the DRI2SwapComplete()
* callback and we'll free it there once we're done. */ * callback and we'll free it there once we're done. */
if (!pPriv->swapsPending) if (!pPriv->swapsPending && !pPriv->blockedClient)
DRI2FreeDrawable(pDraw); DRI2FreeDrawable(pDraw);
} }
Bool
DRI2HasSwapControl(ScreenPtr pScreen)
{
DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
return (ds->ScheduleSwap && ds->GetMSC);
}
Bool Bool
DRI2Connect(ScreenPtr pScreen, unsigned int driverType, int *fd, DRI2Connect(ScreenPtr pScreen, unsigned int driverType, int *fd,
const char **driverName, const char **deviceName) const char **driverName, const char **deviceName)
@ -820,6 +875,7 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
"VDPAU", /* DRI2DriverVDPAU */ "VDPAU", /* DRI2DriverVDPAU */
}; };
unsigned int i; unsigned int i;
CARD8 cur_minor;
if (info->version < 3) if (info->version < 3)
return FALSE; return FALSE;
@ -836,6 +892,7 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
ds->fd = info->fd; ds->fd = info->fd;
ds->deviceName = info->deviceName; ds->deviceName = info->deviceName;
dri2_major = 1;
ds->CreateBuffer = info->CreateBuffer; ds->CreateBuffer = info->CreateBuffer;
ds->DestroyBuffer = info->DestroyBuffer; ds->DestroyBuffer = info->DestroyBuffer;
@ -845,8 +902,15 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
ds->ScheduleSwap = info->ScheduleSwap; ds->ScheduleSwap = info->ScheduleSwap;
ds->ScheduleWaitMSC = info->ScheduleWaitMSC; ds->ScheduleWaitMSC = info->ScheduleWaitMSC;
ds->GetMSC = info->GetMSC; ds->GetMSC = info->GetMSC;
cur_minor = 2;
} else {
cur_minor = 1;
} }
/* Initialize minor if needed and set to minimum provied by DDX */
if (!dri2_minor || dri2_minor > cur_minor)
dri2_minor = cur_minor;
if (info->version == 3 || info->numDrivers == 0) { if (info->version == 3 || info->numDrivers == 0) {
/* Driver too old: use the old-style driverName field */ /* Driver too old: use the old-style driverName field */
ds->numDrivers = 1; ds->numDrivers = 1;

View File

@ -46,6 +46,9 @@ typedef struct {
void *driverPrivate; void *driverPrivate;
} DRI2BufferRec, *DRI2BufferPtr; } DRI2BufferRec, *DRI2BufferPtr;
extern CARD8 dri2_major; /* version of DRI2 supported by DDX */
extern CARD8 dri2_minor;
typedef DRI2BufferRec DRI2Buffer2Rec, *DRI2Buffer2Ptr; typedef DRI2BufferRec DRI2Buffer2Rec, *DRI2Buffer2Ptr;
typedef void (*DRI2SwapEventPtr)(ClientPtr client, void *data, int type, typedef void (*DRI2SwapEventPtr)(ClientPtr client, void *data, int type,
CARD64 ust, CARD64 msc, CARD64 sbc); CARD64 ust, CARD64 msc, CARD64 sbc);
@ -185,6 +188,8 @@ extern _X_EXPORT Bool DRI2ScreenInit(ScreenPtr pScreen,
extern _X_EXPORT void DRI2CloseScreen(ScreenPtr pScreen); extern _X_EXPORT void DRI2CloseScreen(ScreenPtr pScreen);
extern _X_EXPORT Bool DRI2HasSwapControl(ScreenPtr pScreen);
extern _X_EXPORT Bool DRI2Connect(ScreenPtr pScreen, extern _X_EXPORT Bool DRI2Connect(ScreenPtr pScreen,
unsigned int driverType, unsigned int driverType,
int *fd, int *fd,
@ -254,6 +259,7 @@ extern _X_EXPORT Bool DRI2CanFlip(DrawablePtr pDraw);
extern _X_EXPORT Bool DRI2CanExchange(DrawablePtr pDraw); extern _X_EXPORT Bool DRI2CanExchange(DrawablePtr pDraw);
/* Note: use *only* for MSC related waits */
extern _X_EXPORT void DRI2BlockClient(ClientPtr client, DrawablePtr pDraw); extern _X_EXPORT void DRI2BlockClient(ClientPtr client, DrawablePtr pDraw);
extern _X_EXPORT void DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, extern _X_EXPORT void DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw,

View File

@ -80,8 +80,8 @@ ProcDRI2QueryVersion(ClientPtr client)
rep.type = X_Reply; rep.type = X_Reply;
rep.length = 0; rep.length = 0;
rep.sequenceNumber = client->sequence; rep.sequenceNumber = client->sequence;
rep.majorVersion = SERVER_DRI2_MAJOR_VERSION; rep.majorVersion = dri2_major;
rep.minorVersion = SERVER_DRI2_MINOR_VERSION; rep.minorVersion = dri2_minor;
if (client->swapped) { if (client->swapped) {
swaps(&rep.sequenceNumber, n); swaps(&rep.sequenceNumber, n);
@ -384,6 +384,13 @@ ProcDRI2SwapBuffers(ClientPtr client)
DixReadAccess | DixWriteAccess, &pDrawable, &status)) DixReadAccess | DixWriteAccess, &pDrawable, &status))
return status; return status;
/*
* Ensures an out of control client can't exhaust our swap queue, and
* also orders swaps.
*/
if (DRI2ThrottleClient(client, pDrawable))
return client->noClientException;
target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi); target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi); divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi); remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);

View File

@ -51,10 +51,6 @@
#define SERVER_DMX_MINOR_VERSION 2 #define SERVER_DMX_MINOR_VERSION 2
#define SERVER_DMX_PATCH_VERSION 20040604 #define SERVER_DMX_PATCH_VERSION 20040604
/* DRI2 */
#define SERVER_DRI2_MAJOR_VERSION 1
#define SERVER_DRI2_MINOR_VERSION 2
/* Generic event extension */ /* Generic event extension */
#define SERVER_GE_MAJOR_VERSION 1 #define SERVER_GE_MAJOR_VERSION 1
#define SERVER_GE_MINOR_VERSION 0 #define SERVER_GE_MINOR_VERSION 0