From b152ebf4b66368e1cbfda1ae81cef29bf9c00bb7 Mon Sep 17 00:00:00 2001 From: marha Date: Thu, 14 Jan 2010 10:44:09 +0000 Subject: Git update 14/1/2010 --- xorg-server/hw/xfree86/dri2/dri2.c | 403 ++++++++++++++++++++++++++++++++++++- 1 file changed, 399 insertions(+), 4 deletions(-) (limited to 'xorg-server/hw/xfree86/dri2/dri2.c') diff --git a/xorg-server/hw/xfree86/dri2/dri2.c b/xorg-server/hw/xfree86/dri2/dri2.c index d15ced112..3db826e91 100644 --- a/xorg-server/hw/xfree86/dri2/dri2.c +++ b/xorg-server/hw/xfree86/dri2/dri2.c @@ -34,10 +34,12 @@ #include #endif +#include #include #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"); -- cgit v1.2.3