diff options
Diffstat (limited to 'xorg-server/hw/dmx/glxProxy/glxswap.c')
-rw-r--r-- | xorg-server/hw/dmx/glxProxy/glxswap.c | 1076 |
1 files changed, 538 insertions, 538 deletions
diff --git a/xorg-server/hw/dmx/glxProxy/glxswap.c b/xorg-server/hw/dmx/glxProxy/glxswap.c index 1e184f914..1471d8b5f 100644 --- a/xorg-server/hw/dmx/glxProxy/glxswap.c +++ b/xorg-server/hw/dmx/glxProxy/glxswap.c @@ -1,538 +1,538 @@ -/* - * Copyright 2003 Red Hat Inc., Raleigh, North Carolina. - * - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation on the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * Authors: - * Kevin E. Martin <kem@redhat.com> - * - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "dmx.h" -#include "dmxwindow.h" -#include "glxserver.h" -#include "glxswap.h" - -extern int __glXDoSwapBuffers(__GLXclientState *cl, XID drawId, - GLXContextTag tag); - -typedef struct _SwapGroup *SwapGroupPtr; - -static Bool SwapBarrierIsReadyToSwap(GLuint barrier); -static void SwapSwapBarrier(GLuint barrier); -static void UpdateSwapBarrierList(GLuint barrier, - SwapGroupPtr pOldSwap, - SwapGroupPtr pNewSwap); - - -/************************************************************************ - * - * Swap Groups - * - ************************************************************************/ - -typedef struct _SwapGroup { - WindowPtr pWin; - SwapGroupPtr pNext; - - Bool swapping; - Bool sleeping; - GLuint barrier; - - XID drawable; - GLXContextTag tag; - __GLXclientState *clState; -} SwapGroupRec; - - -static void SwapSwapGroup(SwapGroupPtr pSwap) -{ - SwapGroupPtr pCur; - - /* All drawables in swap group are ready to swap, so just swap all - * drawables buffers and then wake up those clients that were - * previously sleeping */ - - for (pCur = pSwap; pCur; pCur = pCur->pNext) { - if (pCur->swapping) { - /* Swap pCur's buffers */ - __glXDoSwapBuffers(pCur->clState, pCur->drawable, pCur->tag); - pCur->swapping = FALSE; - } - - /* Wakeup client */ - if (pCur->sleeping) { - ClientWakeup(pCur->clState->client); - pCur->sleeping = FALSE; - } - } -} - -static Bool SwapGroupIsReadyToSwap(SwapGroupPtr pSwap) -{ - Bool isReady = TRUE; - - /* The swap group is ready to swap when all drawables are ready to - * swap. NOTE: A drawable is also ready to swap if it is not - * currently mapped */ - for (; pSwap; pSwap = pSwap->pNext) { - isReady &= (pSwap->swapping || !pSwap->pWin->mapped); - /* FIXME: Should we use pSwap->pWin->mapped or ...->realized ??? */ - } - - return isReady; -} - -static Bool SGSwapCleanup(ClientPtr client, pointer closure) -{ - /* SwapGroupPtr pSwap = (SwapGroupPtr)closure; */ - - /* This should not be called unless the client has died in which - * case we should remove the buffer from the swap list */ - - return TRUE; -} - -int SGSwapBuffers(__GLXclientState *cl, XID drawId, GLXContextTag tag, - DrawablePtr pDraw) -{ - WindowPtr pWin = (WindowPtr)pDraw; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); - SwapGroupPtr pSwap = pWinPriv->swapGroup; - SwapGroupPtr pCur; - - for (pCur = pSwap; pCur && pCur->pWin != pWin; pCur = pCur->pNext); - if (!pCur) - return BadDrawable; - - pCur->clState = cl; - pCur->drawable = drawId; - pCur->tag = tag; - - /* We are now in the process of swapping */ - pCur->swapping = TRUE; - - if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) { - /* The swap group is bound to a barrier and the barrier is ready - * to swap, so swap all the swap groups that are bound to this - * group's swap barrier */ - SwapSwapBarrier(pSwap->barrier); - } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) { - /* Do the swap if the entire swap group is ready to swap and the - * group is not bound to a swap barrier */ - SwapSwapGroup(pSwap); - } else { - /* The swap group/barrier is not yet ready to swap, so put - * client to sleep until the rest are ready to swap */ - ClientSleep(cl->client, SGSwapCleanup, (pointer)pWin); - pCur->sleeping = TRUE; - } - - return Success; -} - -static void SGWindowUnmapped(WindowPtr pWin) -{ - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); - SwapGroupPtr pSwap = pWinPriv->swapGroup; - - /* Now that one of the windows in the swap group has been unmapped, - * see if the entire swap group/barrier is ready to swap */ - - if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) { - SwapSwapBarrier(pSwap->barrier); - } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) { - SwapSwapGroup(pSwap); - } -} - -static void SGWindowDestroyed(WindowPtr pWin) -{ - JoinSwapGroupSGIX((DrawablePtr)pWin, NULL); -} - -static SwapGroupPtr CreateSwapEntry(WindowPtr pWin) -{ - SwapGroupPtr pEntry; - - /* Allocate new swap group */ - pEntry = xalloc(sizeof(*pEntry)); - if (!pEntry) return NULL; - - /* Initialize swap group */ - pEntry->pWin = pWin; - pEntry->pNext = NULL; - pEntry->swapping = FALSE; - pEntry->sleeping = FALSE; - pEntry->barrier = 0; - /* The following are not initialized until SwapBuffers is called: - * pEntry->drawable - * pEntry->tag - * pEntry->clState - */ - - return pEntry; -} - -static void FreeSwapEntry(SwapGroupPtr pEntry) -{ - /* Since we have removed the drawable from its previous swap group - * and it won't be added to another swap group, the only thing that - * we need to do is to make sure that the drawable's client is not - * sleeping. This could happen if one thread is sleeping, while - * another thread called glxJoinSwapGroup(). Note that all sleeping - * threads should also be swapping, but there is a small window in - * the SGSwapBuffer() logic, above, where swapping can be set but - * sleeping is not. We check both independently here just to be - * pedantic. */ - - /* Handle swap buffer request */ - if (pEntry->swapping) - __glXDoSwapBuffers(pEntry->clState, pEntry->drawable, pEntry->tag); - - /* Wake up client */ - if (pEntry->sleeping) - ClientWakeup(pEntry->clState->client); - - /* We can free the pEntry entry since it has already been removed - * from the swap group list and it won't be needed any longer */ - xfree(pEntry); -} - -int JoinSwapGroupSGIX(DrawablePtr pDraw, DrawablePtr pMember) -{ - if (pDraw->type == DRAWABLE_WINDOW) { - WindowPtr pWin = (WindowPtr)pDraw; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); - SwapGroupPtr pOldSwap = NULL; - SwapGroupPtr pEntry; - - /* If pDraw and pMember are already members of the same swap - * group, just return Success since there is nothing to do */ - for (pEntry = pWinPriv->swapGroup; pEntry; pEntry = pEntry->pNext) - if (pEntry->pWin == (WindowPtr)pMember) - return Success; - - /* Remove pDraw from its current swap group */ - if (pWinPriv->swapGroup) { - SwapGroupPtr pSwapGroup = pWinPriv->swapGroup; - SwapGroupPtr pPrev; - - /* Find old swap entry in swap group and save in pOldSwap - * for later use */ - for (pOldSwap = pWinPriv->swapGroup, pPrev = NULL; - pOldSwap && pOldSwap->pWin != pWin; - pPrev = pOldSwap, pOldSwap = pOldSwap->pNext); - if (!pOldSwap) - return BadDrawable; - - /* Remove pDraw's swap group entry from swap group list */ - if (pPrev) { - pPrev->pNext = pOldSwap->pNext; - } else { - /* pWin is at the head of the swap group list, so we - * need to update all other members of this swap - * group */ - for (pEntry = pOldSwap->pNext; pEntry; pEntry = pEntry->pNext) - DMX_GET_WINDOW_PRIV(pEntry->pWin)->swapGroup - = pOldSwap->pNext; - - /* Update the barrier list as well */ - if (pOldSwap->barrier) - UpdateSwapBarrierList(pOldSwap->barrier, - pOldSwap, pOldSwap->pNext); - - /* Set pSwapGroup to point to the swap group without - * pOldSwap */ - pSwapGroup = pOldSwap->pNext; - } - - /* Check to see if current swap group can now swap since we - * know at this point that pDraw and pMember are guaranteed - * to previously be in different swap groups */ - if (pSwapGroup && SwapGroupIsReadyToSwap(pSwapGroup)) { - SwapSwapGroup(pSwapGroup); - } - - /* Make the old swap entry a standalone group */ - pOldSwap->pNext = NULL; - pOldSwap->barrier = 0; - - /* Reset pWin's swap group */ - pWinPriv->swapGroup = NULL; - pWinPriv->windowDestroyed = NULL; - pWinPriv->windowUnmapped = NULL; - } - - if (!pMember || pMember->type != DRAWABLE_WINDOW) { - /* Free old swap group since it is no longer needed */ - if (pOldSwap) FreeSwapEntry(pOldSwap); - } else if (pDraw == pMember && pOldSwap) { - /* Special case where pDraw was previously created and we - * are now just putting it to its own swap group */ - pWinPriv->swapGroup = pOldSwap; - pWinPriv->windowDestroyed = SGWindowDestroyed; - pWinPriv->windowUnmapped = SGWindowUnmapped; - - /* Check to see if pDraw is ready to swap */ - if (SwapGroupIsReadyToSwap(pOldSwap)) - SwapSwapGroup(pOldSwap); - } else if (pMember->type == DRAWABLE_WINDOW) { - WindowPtr pMemberWin = (WindowPtr)pMember; - dmxWinPrivPtr pMemberPriv = DMX_GET_WINDOW_PRIV(pMemberWin); - SwapGroupPtr pMemberSwapGroup = pMemberPriv->swapGroup; - - /* Finally, how we can add pDraw to pMember's swap group */ - - /* If pMember is not currently in a swap group, then create - * one for it since we are just about to add pDraw to it. */ - if (!pMemberSwapGroup) { - /* Create new swap group */ - pMemberSwapGroup = CreateSwapEntry(pMemberWin); - if (!pMemberSwapGroup) { - if (pOldSwap) FreeSwapEntry(pOldSwap); - return BadAlloc; - } - - /* Set pMember's swap group */ - pMemberPriv->swapGroup = pMemberSwapGroup; - pMemberPriv->windowDestroyed = SGWindowDestroyed; - pMemberPriv->windowUnmapped = SGWindowUnmapped; - } - - /* If pDraw == pMember, that means pDraw was not a member of - * a group previously (or it would have been handled by the - * special case above), so no additional work is required - * since we just created a new swap group for pMember (i.e., - * pDraw). */ - - if (pDraw != pMember) { - /* If pDraw was not previously in a swap group, then create - * an entry for it */ - if (!pOldSwap) { - /* Create new swap group */ - pOldSwap = CreateSwapEntry(pWin); - if (!pOldSwap) { - /* If we just created a swap group for pMember, we - * need to free it here */ - if (pMemberSwapGroup->pNext == NULL) { - FreeSwapEntry(pMemberSwapGroup); - pMemberPriv->swapGroup = NULL; - } - return BadAlloc; - } - } - - /* Find last entry in pMember's swap group */ - for (pEntry = pMemberSwapGroup; - pEntry->pNext; - pEntry = pEntry->pNext); - - /* Add pDraw's swap group entry to pMember's swap group list */ - pEntry->pNext = pOldSwap; - - /* Add pDraw to pMember's swap barrier */ - pOldSwap->barrier = pEntry->barrier; - - /* Set pDraw's swap group */ - pWinPriv->swapGroup = pMemberSwapGroup; - pWinPriv->windowDestroyed = SGWindowDestroyed; - pWinPriv->windowUnmapped = SGWindowUnmapped; - } - } - } - - return Success; -} - - -/************************************************************************ - * - * Swap Barriers - * - ************************************************************************/ - -#define GLX_MAX_SWAP_BARRIERS 10 - -typedef struct _SwapBarrier *SwapBarrierPtr; -typedef struct _SwapBarrier { - SwapGroupPtr pSwap; - SwapBarrierPtr pNext; -} SwapBarrierRec; - -static SwapBarrierPtr SwapBarrierList[GLX_MAX_SWAP_BARRIERS+1]; - -void SwapBarrierInit(void) -{ - int i; - - for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) - SwapBarrierList[i] = NULL; -} - -void SwapBarrierReset(void) -{ - int i; - - for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) { - SwapBarrierPtr pBarrier, pNextBarrier; - for (pBarrier = SwapBarrierList[i]; - pBarrier; - pBarrier = pNextBarrier) { - pNextBarrier = pBarrier->pNext; - xfree(pBarrier); - } - SwapBarrierList[i] = NULL; - } -} - -int QueryMaxSwapBarriersSGIX(int screen) -{ - return GLX_MAX_SWAP_BARRIERS; -} - -static Bool BindSwapGroupToBarrier(GLuint barrier, SwapGroupPtr pSwapGroup) -{ - SwapBarrierPtr pBarrier; - - pBarrier = xalloc(sizeof(*pBarrier)); - if (!pBarrier) return FALSE; - - /* Add the swap group to barrier's list */ - pBarrier->pSwap = pSwapGroup; - pBarrier->pNext = SwapBarrierList[barrier]; - SwapBarrierList[barrier] = pBarrier; - - return TRUE; -} - -static Bool UnbindSwapGroupFromBarrier(GLuint barrier, SwapGroupPtr pSwapGroup) -{ - SwapBarrierPtr pBarrier, pPrevBarrier; - - /* Find the swap group in barrier's list */ - for (pBarrier = SwapBarrierList[barrier], pPrevBarrier = NULL; - pBarrier && pBarrier->pSwap != pSwapGroup; - pPrevBarrier = pBarrier, pBarrier = pBarrier->pNext); - if (!pBarrier) return FALSE; - - /* Remove the swap group from barrier's list */ - if (pPrevBarrier) pPrevBarrier->pNext = pBarrier->pNext; - else SwapBarrierList[barrier] = pBarrier->pNext; - - /* Free memory */ - xfree(pBarrier); - - return TRUE; -} - -static void UpdateSwapBarrierList(GLuint barrier, - SwapGroupPtr pOldSwap, - SwapGroupPtr pNewSwap) -{ - SwapBarrierPtr pBarrier; - - /* If the old swap group is being destroyed, then we need to remove - * the swap group from the list entirely */ - if (!pNewSwap) { - UnbindSwapGroupFromBarrier(barrier, pOldSwap); - return; - } - - /* Otherwise, find the old swap group in the barrier list and change - * it to the new swap group */ - for (pBarrier = SwapBarrierList[barrier]; - pBarrier; - pBarrier = pBarrier->pNext) { - if (pBarrier->pSwap == pOldSwap) { - pBarrier->pSwap = pNewSwap; - return; - } - } -} - -static Bool SwapBarrierIsReadyToSwap(GLuint barrier) -{ - SwapBarrierPtr pBarrier; - Bool isReady = TRUE; - - /* The swap barier is ready to swap when swap groups that are bound - * to barrier are ready to swap */ - for (pBarrier = SwapBarrierList[barrier]; - pBarrier; - pBarrier = pBarrier->pNext) - isReady &= SwapGroupIsReadyToSwap(pBarrier->pSwap); - - return isReady; -} - -static void SwapSwapBarrier(GLuint barrier) -{ - SwapBarrierPtr pBarrier; - - /* Swap each group that is a member of this barrier */ - for (pBarrier = SwapBarrierList[barrier]; - pBarrier; - pBarrier = pBarrier->pNext) - SwapSwapGroup(pBarrier->pSwap); -} - -int BindSwapBarrierSGIX(DrawablePtr pDraw, int barrier) -{ - /* FIXME: Check for errors when pDraw->type != DRAWABLE_WINDOW */ - - if (barrier < 0 || barrier > GLX_MAX_SWAP_BARRIERS) - return BadValue; - - if (pDraw->type == DRAWABLE_WINDOW) { - WindowPtr pWin = (WindowPtr)pDraw; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); - SwapGroupPtr pSwapGroup = pWinPriv->swapGroup; - SwapGroupPtr pCur; - - if (!pSwapGroup) return BadDrawable; - if (barrier && pSwapGroup->barrier) return BadValue; - - /* Update the swap barrier list */ - if (barrier) { - if (!BindSwapGroupToBarrier(barrier, pSwapGroup)) - return BadAlloc; - } else { - if (!UnbindSwapGroupFromBarrier(pSwapGroup->barrier, pSwapGroup)) - return BadDrawable; - } - - /* Set the barrier for each member of this swap group */ - for (pCur = pSwapGroup; pCur; pCur = pCur->pNext) - pCur->barrier = barrier; - } - - return Success; -} +/*
+ * Copyright 2003 Red Hat Inc., Raleigh, North Carolina.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation on the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * Authors:
+ * Kevin E. Martin <kem@redhat.com>
+ *
+ */
+
+#ifdef HAVE_DMX_CONFIG_H
+#include <dmx-config.h>
+#endif
+
+#include "dmx.h"
+#include "dmxwindow.h"
+#include "glxserver.h"
+#include "glxswap.h"
+
+extern int __glXDoSwapBuffers(__GLXclientState *cl, XID drawId,
+ GLXContextTag tag);
+
+typedef struct _SwapGroup *SwapGroupPtr;
+
+static Bool SwapBarrierIsReadyToSwap(GLuint barrier);
+static void SwapSwapBarrier(GLuint barrier);
+static void UpdateSwapBarrierList(GLuint barrier,
+ SwapGroupPtr pOldSwap,
+ SwapGroupPtr pNewSwap);
+
+
+/************************************************************************
+ *
+ * Swap Groups
+ *
+ ************************************************************************/
+
+typedef struct _SwapGroup {
+ WindowPtr pWin;
+ SwapGroupPtr pNext;
+
+ Bool swapping;
+ Bool sleeping;
+ GLuint barrier;
+
+ XID drawable;
+ GLXContextTag tag;
+ __GLXclientState *clState;
+} SwapGroupRec;
+
+
+static void SwapSwapGroup(SwapGroupPtr pSwap)
+{
+ SwapGroupPtr pCur;
+
+ /* All drawables in swap group are ready to swap, so just swap all
+ * drawables buffers and then wake up those clients that were
+ * previously sleeping */
+
+ for (pCur = pSwap; pCur; pCur = pCur->pNext) {
+ if (pCur->swapping) {
+ /* Swap pCur's buffers */
+ __glXDoSwapBuffers(pCur->clState, pCur->drawable, pCur->tag);
+ pCur->swapping = FALSE;
+ }
+
+ /* Wakeup client */
+ if (pCur->sleeping) {
+ ClientWakeup(pCur->clState->client);
+ pCur->sleeping = FALSE;
+ }
+ }
+}
+
+static Bool SwapGroupIsReadyToSwap(SwapGroupPtr pSwap)
+{
+ Bool isReady = TRUE;
+
+ /* The swap group is ready to swap when all drawables are ready to
+ * swap. NOTE: A drawable is also ready to swap if it is not
+ * currently mapped */
+ for (; pSwap; pSwap = pSwap->pNext) {
+ isReady &= (pSwap->swapping || !pSwap->pWin->mapped);
+ /* FIXME: Should we use pSwap->pWin->mapped or ...->realized ??? */
+ }
+
+ return isReady;
+}
+
+static Bool SGSwapCleanup(ClientPtr client, pointer closure)
+{
+ /* SwapGroupPtr pSwap = (SwapGroupPtr)closure; */
+
+ /* This should not be called unless the client has died in which
+ * case we should remove the buffer from the swap list */
+
+ return TRUE;
+}
+
+int SGSwapBuffers(__GLXclientState *cl, XID drawId, GLXContextTag tag,
+ DrawablePtr pDraw)
+{
+ WindowPtr pWin = (WindowPtr)pDraw;
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
+ SwapGroupPtr pSwap = pWinPriv->swapGroup;
+ SwapGroupPtr pCur;
+
+ for (pCur = pSwap; pCur && pCur->pWin != pWin; pCur = pCur->pNext);
+ if (!pCur)
+ return BadDrawable;
+
+ pCur->clState = cl;
+ pCur->drawable = drawId;
+ pCur->tag = tag;
+
+ /* We are now in the process of swapping */
+ pCur->swapping = TRUE;
+
+ if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) {
+ /* The swap group is bound to a barrier and the barrier is ready
+ * to swap, so swap all the swap groups that are bound to this
+ * group's swap barrier */
+ SwapSwapBarrier(pSwap->barrier);
+ } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) {
+ /* Do the swap if the entire swap group is ready to swap and the
+ * group is not bound to a swap barrier */
+ SwapSwapGroup(pSwap);
+ } else {
+ /* The swap group/barrier is not yet ready to swap, so put
+ * client to sleep until the rest are ready to swap */
+ ClientSleep(cl->client, SGSwapCleanup, (pointer)pWin);
+ pCur->sleeping = TRUE;
+ }
+
+ return Success;
+}
+
+static void SGWindowUnmapped(WindowPtr pWin)
+{
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
+ SwapGroupPtr pSwap = pWinPriv->swapGroup;
+
+ /* Now that one of the windows in the swap group has been unmapped,
+ * see if the entire swap group/barrier is ready to swap */
+
+ if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) {
+ SwapSwapBarrier(pSwap->barrier);
+ } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) {
+ SwapSwapGroup(pSwap);
+ }
+}
+
+static void SGWindowDestroyed(WindowPtr pWin)
+{
+ JoinSwapGroupSGIX((DrawablePtr)pWin, NULL);
+}
+
+static SwapGroupPtr CreateSwapEntry(WindowPtr pWin)
+{
+ SwapGroupPtr pEntry;
+
+ /* Allocate new swap group */
+ pEntry = malloc(sizeof(*pEntry));
+ if (!pEntry) return NULL;
+
+ /* Initialize swap group */
+ pEntry->pWin = pWin;
+ pEntry->pNext = NULL;
+ pEntry->swapping = FALSE;
+ pEntry->sleeping = FALSE;
+ pEntry->barrier = 0;
+ /* The following are not initialized until SwapBuffers is called:
+ * pEntry->drawable
+ * pEntry->tag
+ * pEntry->clState
+ */
+
+ return pEntry;
+}
+
+static void FreeSwapEntry(SwapGroupPtr pEntry)
+{
+ /* Since we have removed the drawable from its previous swap group
+ * and it won't be added to another swap group, the only thing that
+ * we need to do is to make sure that the drawable's client is not
+ * sleeping. This could happen if one thread is sleeping, while
+ * another thread called glxJoinSwapGroup(). Note that all sleeping
+ * threads should also be swapping, but there is a small window in
+ * the SGSwapBuffer() logic, above, where swapping can be set but
+ * sleeping is not. We check both independently here just to be
+ * pedantic. */
+
+ /* Handle swap buffer request */
+ if (pEntry->swapping)
+ __glXDoSwapBuffers(pEntry->clState, pEntry->drawable, pEntry->tag);
+
+ /* Wake up client */
+ if (pEntry->sleeping)
+ ClientWakeup(pEntry->clState->client);
+
+ /* We can free the pEntry entry since it has already been removed
+ * from the swap group list and it won't be needed any longer */
+ free(pEntry);
+}
+
+int JoinSwapGroupSGIX(DrawablePtr pDraw, DrawablePtr pMember)
+{
+ if (pDraw->type == DRAWABLE_WINDOW) {
+ WindowPtr pWin = (WindowPtr)pDraw;
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
+ SwapGroupPtr pOldSwap = NULL;
+ SwapGroupPtr pEntry;
+
+ /* If pDraw and pMember are already members of the same swap
+ * group, just return Success since there is nothing to do */
+ for (pEntry = pWinPriv->swapGroup; pEntry; pEntry = pEntry->pNext)
+ if (pEntry->pWin == (WindowPtr)pMember)
+ return Success;
+
+ /* Remove pDraw from its current swap group */
+ if (pWinPriv->swapGroup) {
+ SwapGroupPtr pSwapGroup = pWinPriv->swapGroup;
+ SwapGroupPtr pPrev;
+
+ /* Find old swap entry in swap group and save in pOldSwap
+ * for later use */
+ for (pOldSwap = pWinPriv->swapGroup, pPrev = NULL;
+ pOldSwap && pOldSwap->pWin != pWin;
+ pPrev = pOldSwap, pOldSwap = pOldSwap->pNext);
+ if (!pOldSwap)
+ return BadDrawable;
+
+ /* Remove pDraw's swap group entry from swap group list */
+ if (pPrev) {
+ pPrev->pNext = pOldSwap->pNext;
+ } else {
+ /* pWin is at the head of the swap group list, so we
+ * need to update all other members of this swap
+ * group */
+ for (pEntry = pOldSwap->pNext; pEntry; pEntry = pEntry->pNext)
+ DMX_GET_WINDOW_PRIV(pEntry->pWin)->swapGroup
+ = pOldSwap->pNext;
+
+ /* Update the barrier list as well */
+ if (pOldSwap->barrier)
+ UpdateSwapBarrierList(pOldSwap->barrier,
+ pOldSwap, pOldSwap->pNext);
+
+ /* Set pSwapGroup to point to the swap group without
+ * pOldSwap */
+ pSwapGroup = pOldSwap->pNext;
+ }
+
+ /* Check to see if current swap group can now swap since we
+ * know at this point that pDraw and pMember are guaranteed
+ * to previously be in different swap groups */
+ if (pSwapGroup && SwapGroupIsReadyToSwap(pSwapGroup)) {
+ SwapSwapGroup(pSwapGroup);
+ }
+
+ /* Make the old swap entry a standalone group */
+ pOldSwap->pNext = NULL;
+ pOldSwap->barrier = 0;
+
+ /* Reset pWin's swap group */
+ pWinPriv->swapGroup = NULL;
+ pWinPriv->windowDestroyed = NULL;
+ pWinPriv->windowUnmapped = NULL;
+ }
+
+ if (!pMember || pMember->type != DRAWABLE_WINDOW) {
+ /* Free old swap group since it is no longer needed */
+ if (pOldSwap) FreeSwapEntry(pOldSwap);
+ } else if (pDraw == pMember && pOldSwap) {
+ /* Special case where pDraw was previously created and we
+ * are now just putting it to its own swap group */
+ pWinPriv->swapGroup = pOldSwap;
+ pWinPriv->windowDestroyed = SGWindowDestroyed;
+ pWinPriv->windowUnmapped = SGWindowUnmapped;
+
+ /* Check to see if pDraw is ready to swap */
+ if (SwapGroupIsReadyToSwap(pOldSwap))
+ SwapSwapGroup(pOldSwap);
+ } else if (pMember->type == DRAWABLE_WINDOW) {
+ WindowPtr pMemberWin = (WindowPtr)pMember;
+ dmxWinPrivPtr pMemberPriv = DMX_GET_WINDOW_PRIV(pMemberWin);
+ SwapGroupPtr pMemberSwapGroup = pMemberPriv->swapGroup;
+
+ /* Finally, how we can add pDraw to pMember's swap group */
+
+ /* If pMember is not currently in a swap group, then create
+ * one for it since we are just about to add pDraw to it. */
+ if (!pMemberSwapGroup) {
+ /* Create new swap group */
+ pMemberSwapGroup = CreateSwapEntry(pMemberWin);
+ if (!pMemberSwapGroup) {
+ if (pOldSwap) FreeSwapEntry(pOldSwap);
+ return BadAlloc;
+ }
+
+ /* Set pMember's swap group */
+ pMemberPriv->swapGroup = pMemberSwapGroup;
+ pMemberPriv->windowDestroyed = SGWindowDestroyed;
+ pMemberPriv->windowUnmapped = SGWindowUnmapped;
+ }
+
+ /* If pDraw == pMember, that means pDraw was not a member of
+ * a group previously (or it would have been handled by the
+ * special case above), so no additional work is required
+ * since we just created a new swap group for pMember (i.e.,
+ * pDraw). */
+
+ if (pDraw != pMember) {
+ /* If pDraw was not previously in a swap group, then create
+ * an entry for it */
+ if (!pOldSwap) {
+ /* Create new swap group */
+ pOldSwap = CreateSwapEntry(pWin);
+ if (!pOldSwap) {
+ /* If we just created a swap group for pMember, we
+ * need to free it here */
+ if (pMemberSwapGroup->pNext == NULL) {
+ FreeSwapEntry(pMemberSwapGroup);
+ pMemberPriv->swapGroup = NULL;
+ }
+ return BadAlloc;
+ }
+ }
+
+ /* Find last entry in pMember's swap group */
+ for (pEntry = pMemberSwapGroup;
+ pEntry->pNext;
+ pEntry = pEntry->pNext);
+
+ /* Add pDraw's swap group entry to pMember's swap group list */
+ pEntry->pNext = pOldSwap;
+
+ /* Add pDraw to pMember's swap barrier */
+ pOldSwap->barrier = pEntry->barrier;
+
+ /* Set pDraw's swap group */
+ pWinPriv->swapGroup = pMemberSwapGroup;
+ pWinPriv->windowDestroyed = SGWindowDestroyed;
+ pWinPriv->windowUnmapped = SGWindowUnmapped;
+ }
+ }
+ }
+
+ return Success;
+}
+
+
+/************************************************************************
+ *
+ * Swap Barriers
+ *
+ ************************************************************************/
+
+#define GLX_MAX_SWAP_BARRIERS 10
+
+typedef struct _SwapBarrier *SwapBarrierPtr;
+typedef struct _SwapBarrier {
+ SwapGroupPtr pSwap;
+ SwapBarrierPtr pNext;
+} SwapBarrierRec;
+
+static SwapBarrierPtr SwapBarrierList[GLX_MAX_SWAP_BARRIERS+1];
+
+void SwapBarrierInit(void)
+{
+ int i;
+
+ for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++)
+ SwapBarrierList[i] = NULL;
+}
+
+void SwapBarrierReset(void)
+{
+ int i;
+
+ for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) {
+ SwapBarrierPtr pBarrier, pNextBarrier;
+ for (pBarrier = SwapBarrierList[i];
+ pBarrier;
+ pBarrier = pNextBarrier) {
+ pNextBarrier = pBarrier->pNext;
+ free(pBarrier);
+ }
+ SwapBarrierList[i] = NULL;
+ }
+}
+
+int QueryMaxSwapBarriersSGIX(int screen)
+{
+ return GLX_MAX_SWAP_BARRIERS;
+}
+
+static Bool BindSwapGroupToBarrier(GLuint barrier, SwapGroupPtr pSwapGroup)
+{
+ SwapBarrierPtr pBarrier;
+
+ pBarrier = malloc(sizeof(*pBarrier));
+ if (!pBarrier) return FALSE;
+
+ /* Add the swap group to barrier's list */
+ pBarrier->pSwap = pSwapGroup;
+ pBarrier->pNext = SwapBarrierList[barrier];
+ SwapBarrierList[barrier] = pBarrier;
+
+ return TRUE;
+}
+
+static Bool UnbindSwapGroupFromBarrier(GLuint barrier, SwapGroupPtr pSwapGroup)
+{
+ SwapBarrierPtr pBarrier, pPrevBarrier;
+
+ /* Find the swap group in barrier's list */
+ for (pBarrier = SwapBarrierList[barrier], pPrevBarrier = NULL;
+ pBarrier && pBarrier->pSwap != pSwapGroup;
+ pPrevBarrier = pBarrier, pBarrier = pBarrier->pNext);
+ if (!pBarrier) return FALSE;
+
+ /* Remove the swap group from barrier's list */
+ if (pPrevBarrier) pPrevBarrier->pNext = pBarrier->pNext;
+ else SwapBarrierList[barrier] = pBarrier->pNext;
+
+ /* Free memory */
+ free(pBarrier);
+
+ return TRUE;
+}
+
+static void UpdateSwapBarrierList(GLuint barrier,
+ SwapGroupPtr pOldSwap,
+ SwapGroupPtr pNewSwap)
+{
+ SwapBarrierPtr pBarrier;
+
+ /* If the old swap group is being destroyed, then we need to remove
+ * the swap group from the list entirely */
+ if (!pNewSwap) {
+ UnbindSwapGroupFromBarrier(barrier, pOldSwap);
+ return;
+ }
+
+ /* Otherwise, find the old swap group in the barrier list and change
+ * it to the new swap group */
+ for (pBarrier = SwapBarrierList[barrier];
+ pBarrier;
+ pBarrier = pBarrier->pNext) {
+ if (pBarrier->pSwap == pOldSwap) {
+ pBarrier->pSwap = pNewSwap;
+ return;
+ }
+ }
+}
+
+static Bool SwapBarrierIsReadyToSwap(GLuint barrier)
+{
+ SwapBarrierPtr pBarrier;
+ Bool isReady = TRUE;
+
+ /* The swap barier is ready to swap when swap groups that are bound
+ * to barrier are ready to swap */
+ for (pBarrier = SwapBarrierList[barrier];
+ pBarrier;
+ pBarrier = pBarrier->pNext)
+ isReady &= SwapGroupIsReadyToSwap(pBarrier->pSwap);
+
+ return isReady;
+}
+
+static void SwapSwapBarrier(GLuint barrier)
+{
+ SwapBarrierPtr pBarrier;
+
+ /* Swap each group that is a member of this barrier */
+ for (pBarrier = SwapBarrierList[barrier];
+ pBarrier;
+ pBarrier = pBarrier->pNext)
+ SwapSwapGroup(pBarrier->pSwap);
+}
+
+int BindSwapBarrierSGIX(DrawablePtr pDraw, int barrier)
+{
+ /* FIXME: Check for errors when pDraw->type != DRAWABLE_WINDOW */
+
+ if (barrier < 0 || barrier > GLX_MAX_SWAP_BARRIERS)
+ return BadValue;
+
+ if (pDraw->type == DRAWABLE_WINDOW) {
+ WindowPtr pWin = (WindowPtr)pDraw;
+ dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
+ SwapGroupPtr pSwapGroup = pWinPriv->swapGroup;
+ SwapGroupPtr pCur;
+
+ if (!pSwapGroup) return BadDrawable;
+ if (barrier && pSwapGroup->barrier) return BadValue;
+
+ /* Update the swap barrier list */
+ if (barrier) {
+ if (!BindSwapGroupToBarrier(barrier, pSwapGroup))
+ return BadAlloc;
+ } else {
+ if (!UnbindSwapGroupFromBarrier(pSwapGroup->barrier, pSwapGroup))
+ return BadDrawable;
+ }
+
+ /* Set the barrier for each member of this swap group */
+ for (pCur = pSwapGroup; pCur; pCur = pCur->pNext)
+ pCur->barrier = barrier;
+ }
+
+ return Success;
+}
|