]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/xserver.git/blob - hw/dmx/glxProxy/glxswap.c
Imported Upstream version 1.11.4
[glsdk/xserver.git] / hw / dmx / glxProxy / glxswap.c
1 /*
2  * Copyright 2003 Red Hat Inc., Raleigh, North Carolina.
3  *
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation on the rights to use, copy, modify, merge,
10  * publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial
16  * portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
28 /*
29  * Authors:
30  *   Kevin E. Martin <kem@redhat.com>
31  *
32  */
34 #ifdef HAVE_DMX_CONFIG_H
35 #include <dmx-config.h>
36 #endif
38 #include "dmx.h"
39 #include "dmxwindow.h"
40 #include "glxserver.h"
41 #include "glxswap.h"
43 extern int __glXDoSwapBuffers(__GLXclientState *cl, XID drawId,
44                               GLXContextTag tag);
46 typedef struct _SwapGroup *SwapGroupPtr;
48 static Bool SwapBarrierIsReadyToSwap(GLuint barrier);
49 static void SwapSwapBarrier(GLuint barrier);
50 static void UpdateSwapBarrierList(GLuint barrier,
51                                   SwapGroupPtr pOldSwap,
52                                   SwapGroupPtr pNewSwap);
55 /************************************************************************
56  *
57  * Swap Groups
58  *
59  ************************************************************************/
61 typedef struct _SwapGroup {
62     WindowPtr         pWin;
63     SwapGroupPtr      pNext;
65     Bool              swapping;
66     Bool              sleeping;
67     GLuint            barrier;
69     XID               drawable;
70     GLXContextTag     tag;
71     __GLXclientState *clState;
72 } SwapGroupRec;
75 static void SwapSwapGroup(SwapGroupPtr pSwap)
76 {
77     SwapGroupPtr  pCur;
79     /* All drawables in swap group are ready to swap, so just swap all
80      * drawables buffers and then wake up those clients that were
81      * previously sleeping */
83     for (pCur = pSwap; pCur; pCur = pCur->pNext) {
84         if (pCur->swapping) {
85             /* Swap pCur's buffers */
86             __glXDoSwapBuffers(pCur->clState, pCur->drawable, pCur->tag);
87             pCur->swapping = FALSE;
88         }
90         /* Wakeup client */
91         if (pCur->sleeping) {
92             ClientWakeup(pCur->clState->client);
93             pCur->sleeping = FALSE;
94         }
95     }
96 }
98 static Bool SwapGroupIsReadyToSwap(SwapGroupPtr pSwap)
99 {
100     Bool  isReady = TRUE;
102     /* The swap group is ready to swap when all drawables are ready to
103      * swap.  NOTE: A drawable is also ready to swap if it is not
104      * currently mapped */
105     for (; pSwap; pSwap = pSwap->pNext) {
106         isReady &= (pSwap->swapping || !pSwap->pWin->mapped);
107         /* FIXME: Should we use pSwap->pWin->mapped or ...->realized ??? */
108     }
110     return isReady;
113 static Bool SGSwapCleanup(ClientPtr client, pointer closure)
115     /* SwapGroupPtr  pSwap = (SwapGroupPtr)closure; */
117     /* This should not be called unless the client has died in which
118      * case we should remove the buffer from the swap list */
120     return TRUE;
123 int SGSwapBuffers(__GLXclientState *cl, XID drawId, GLXContextTag tag,
124                   DrawablePtr pDraw)
126     WindowPtr      pWin     = (WindowPtr)pDraw;
127     dmxWinPrivPtr  pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
128     SwapGroupPtr   pSwap    = pWinPriv->swapGroup;
129     SwapGroupPtr   pCur;
131     for (pCur = pSwap; pCur && pCur->pWin != pWin; pCur = pCur->pNext);
132     if (!pCur)
133         return BadDrawable;
135     pCur->clState  = cl;
136     pCur->drawable = drawId;
137     pCur->tag      = tag;
139     /* We are now in the process of swapping */
140     pCur->swapping = TRUE;
142     if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) {
143         /* The swap group is bound to a barrier and the barrier is ready
144          * to swap, so swap all the swap groups that are bound to this
145          * group's swap barrier */
146         SwapSwapBarrier(pSwap->barrier);
147     } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) {
148         /* Do the swap if the entire swap group is ready to swap and the
149          * group is not bound to a swap barrier */
150         SwapSwapGroup(pSwap);
151     } else {
152         /* The swap group/barrier is not yet ready to swap, so put
153          * client to sleep until the rest are ready to swap */
154         ClientSleep(cl->client, SGSwapCleanup, (pointer)pWin);
155         pCur->sleeping = TRUE;
156     }
158     return Success;
161 static void SGWindowUnmapped(WindowPtr pWin)
163     dmxWinPrivPtr  pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
164     SwapGroupPtr   pSwap    = pWinPriv->swapGroup;
166     /* Now that one of the windows in the swap group has been unmapped,
167      * see if the entire swap group/barrier is ready to swap */
169     if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) {
170         SwapSwapBarrier(pSwap->barrier);
171     } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) {
172         SwapSwapGroup(pSwap);
173     }
176 static void SGWindowDestroyed(WindowPtr pWin)
178     JoinSwapGroupSGIX((DrawablePtr)pWin, NULL);
181 static SwapGroupPtr CreateSwapEntry(WindowPtr pWin)
183     SwapGroupPtr  pEntry;
185     /* Allocate new swap group */
186     pEntry = malloc(sizeof(*pEntry));
187     if (!pEntry) return NULL;
189     /* Initialize swap group */
190     pEntry->pWin     = pWin;
191     pEntry->pNext    = NULL;
192     pEntry->swapping = FALSE;
193     pEntry->sleeping = FALSE;
194     pEntry->barrier  = 0;
195     /* The following are not initialized until SwapBuffers is called:
196      *     pEntry->drawable
197      *     pEntry->tag
198      *     pEntry->clState
199      */
201     return pEntry;
204 static void FreeSwapEntry(SwapGroupPtr pEntry)
206     /* Since we have removed the drawable from its previous swap group
207      * and it won't be added to another swap group, the only thing that
208      * we need to do is to make sure that the drawable's client is not
209      * sleeping.  This could happen if one thread is sleeping, while
210      * another thread called glxJoinSwapGroup().  Note that all sleeping
211      * threads should also be swapping, but there is a small window in
212      * the SGSwapBuffer() logic, above, where swapping can be set but
213      * sleeping is not.  We check both independently here just to be
214      * pedantic. */
216     /* Handle swap buffer request */
217     if (pEntry->swapping)
218         __glXDoSwapBuffers(pEntry->clState, pEntry->drawable, pEntry->tag);
220     /* Wake up client */
221     if (pEntry->sleeping)
222         ClientWakeup(pEntry->clState->client);
224     /* We can free the pEntry entry since it has already been removed
225      * from the swap group list and it won't be needed any longer */
226     free(pEntry);
229 int JoinSwapGroupSGIX(DrawablePtr pDraw, DrawablePtr pMember)
231     if (pDraw->type == DRAWABLE_WINDOW) {
232         WindowPtr      pWin     = (WindowPtr)pDraw;
233         dmxWinPrivPtr  pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
234         SwapGroupPtr   pOldSwap = NULL;
235         SwapGroupPtr   pEntry;
237         /* If pDraw and pMember are already members of the same swap
238          * group, just return Success since there is nothing to do */
239         for (pEntry = pWinPriv->swapGroup; pEntry; pEntry = pEntry->pNext)
240             if (pEntry->pWin == (WindowPtr)pMember)
241                 return Success;
243         /* Remove pDraw from its current swap group */
244         if (pWinPriv->swapGroup) {
245             SwapGroupPtr  pSwapGroup = pWinPriv->swapGroup;
246             SwapGroupPtr  pPrev;
248             /* Find old swap entry in swap group and save in pOldSwap
249              * for later use */
250             for (pOldSwap = pWinPriv->swapGroup, pPrev = NULL;
251                  pOldSwap && pOldSwap->pWin != pWin;
252                  pPrev = pOldSwap, pOldSwap = pOldSwap->pNext);
253             if (!pOldSwap)
254                 return BadDrawable;
256             /* Remove pDraw's swap group entry from swap group list */
257             if (pPrev) {
258                 pPrev->pNext = pOldSwap->pNext;
259             } else {
260                 /* pWin is at the head of the swap group list, so we
261                  * need to update all other members of this swap
262                  * group */
263                 for (pEntry = pOldSwap->pNext; pEntry; pEntry = pEntry->pNext)
264                     DMX_GET_WINDOW_PRIV(pEntry->pWin)->swapGroup
265                         = pOldSwap->pNext;
267                 /* Update the barrier list as well */
268                 if (pOldSwap->barrier)
269                     UpdateSwapBarrierList(pOldSwap->barrier,
270                                           pOldSwap, pOldSwap->pNext);
272                 /* Set pSwapGroup to point to the swap group without
273                  * pOldSwap */
274                 pSwapGroup = pOldSwap->pNext;
275             }
277             /* Check to see if current swap group can now swap since we
278              * know at this point that pDraw and pMember are guaranteed
279              * to previously be in different swap groups */
280             if (pSwapGroup && SwapGroupIsReadyToSwap(pSwapGroup)) {
281                 SwapSwapGroup(pSwapGroup);
282             }
284             /* Make the old swap entry a standalone group */
285             pOldSwap->pNext = NULL;
286             pOldSwap->barrier = 0;
288             /* Reset pWin's swap group */
289             pWinPriv->swapGroup = NULL;
290             pWinPriv->windowDestroyed = NULL;
291             pWinPriv->windowUnmapped = NULL;
292         }
294         if (!pMember || pMember->type != DRAWABLE_WINDOW) {
295             /* Free old swap group since it is no longer needed */
296             if (pOldSwap) FreeSwapEntry(pOldSwap);
297         } else if (pDraw == pMember && pOldSwap) {
298             /* Special case where pDraw was previously created and we
299              * are now just putting it to its own swap group */
300             pWinPriv->swapGroup = pOldSwap;
301             pWinPriv->windowDestroyed = SGWindowDestroyed;
302             pWinPriv->windowUnmapped = SGWindowUnmapped;
304             /* Check to see if pDraw is ready to swap */
305             if (SwapGroupIsReadyToSwap(pOldSwap))
306                 SwapSwapGroup(pOldSwap);
307         } else if (pMember->type == DRAWABLE_WINDOW) {
308             WindowPtr      pMemberWin       = (WindowPtr)pMember;
309             dmxWinPrivPtr  pMemberPriv      = DMX_GET_WINDOW_PRIV(pMemberWin);
310             SwapGroupPtr   pMemberSwapGroup = pMemberPriv->swapGroup;
312             /* Finally, how we can add pDraw to pMember's swap group */
314             /* If pMember is not currently in a swap group, then create
315              * one for it since we are just about to add pDraw to it. */
316             if (!pMemberSwapGroup) {
317                 /* Create new swap group */
318                 pMemberSwapGroup = CreateSwapEntry(pMemberWin);
319                 if (!pMemberSwapGroup) {
320                     if (pOldSwap) FreeSwapEntry(pOldSwap);
321                     return BadAlloc;
322                 }
324                 /* Set pMember's swap group */
325                 pMemberPriv->swapGroup = pMemberSwapGroup;
326                 pMemberPriv->windowDestroyed = SGWindowDestroyed;
327                 pMemberPriv->windowUnmapped = SGWindowUnmapped;
328             }
330             /* If pDraw == pMember, that means pDraw was not a member of
331              * a group previously (or it would have been handled by the
332              * special case above), so no additional work is required
333              * since we just created a new swap group for pMember (i.e.,
334              * pDraw). */
336             if (pDraw != pMember) {
337                 /* If pDraw was not previously in a swap group, then create
338                  * an entry for it */
339                 if (!pOldSwap) {
340                     /* Create new swap group */
341                     pOldSwap = CreateSwapEntry(pWin);
342                     if (!pOldSwap) {
343                         /* If we just created a swap group for pMember, we
344                          * need to free it here */
345                         if (pMemberSwapGroup->pNext == NULL) {
346                             FreeSwapEntry(pMemberSwapGroup);
347                             pMemberPriv->swapGroup = NULL;
348                         }
349                         return BadAlloc;
350                     }
351                 }
353                 /* Find last entry in pMember's swap group */
354                 for (pEntry = pMemberSwapGroup;
355                      pEntry->pNext;
356                      pEntry = pEntry->pNext);
358                 /* Add pDraw's swap group entry to pMember's swap group list */
359                 pEntry->pNext = pOldSwap;
361                 /* Add pDraw to pMember's swap barrier */
362                 pOldSwap->barrier = pEntry->barrier;
364                 /* Set pDraw's swap group */
365                 pWinPriv->swapGroup = pMemberSwapGroup;
366                 pWinPriv->windowDestroyed = SGWindowDestroyed;
367                 pWinPriv->windowUnmapped = SGWindowUnmapped;
368             }
369         }
370     }
372     return Success;
376 /************************************************************************
377  *
378  * Swap Barriers
379  *
380  ************************************************************************/
382 #define GLX_MAX_SWAP_BARRIERS 10
384 typedef struct _SwapBarrier *SwapBarrierPtr;
385 typedef struct _SwapBarrier {
386     SwapGroupPtr    pSwap;
387     SwapBarrierPtr  pNext;
388 } SwapBarrierRec;
390 static SwapBarrierPtr SwapBarrierList[GLX_MAX_SWAP_BARRIERS+1];
392 void SwapBarrierInit(void)
394     int  i;
396     for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++)
397         SwapBarrierList[i] = NULL;
400 void SwapBarrierReset(void)
402     int  i;
404     for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) {
405         SwapBarrierPtr  pBarrier, pNextBarrier;
406         for (pBarrier = SwapBarrierList[i];
407              pBarrier;
408              pBarrier = pNextBarrier) {
409             pNextBarrier = pBarrier->pNext;
410             free(pBarrier);
411         }
412         SwapBarrierList[i] = NULL;
413     }
416 int QueryMaxSwapBarriersSGIX(int screen)
418     return GLX_MAX_SWAP_BARRIERS;
421 static Bool BindSwapGroupToBarrier(GLuint barrier, SwapGroupPtr pSwapGroup)
423     SwapBarrierPtr  pBarrier;
425     pBarrier = malloc(sizeof(*pBarrier));
426     if (!pBarrier) return FALSE;
428     /* Add the swap group to barrier's list */
429     pBarrier->pSwap = pSwapGroup;
430     pBarrier->pNext = SwapBarrierList[barrier];
431     SwapBarrierList[barrier] = pBarrier;
433     return TRUE;
436 static Bool UnbindSwapGroupFromBarrier(GLuint barrier, SwapGroupPtr pSwapGroup)
438     SwapBarrierPtr  pBarrier, pPrevBarrier;
440     /* Find the swap group in barrier's list */
441     for (pBarrier = SwapBarrierList[barrier], pPrevBarrier = NULL;
442          pBarrier && pBarrier->pSwap != pSwapGroup;
443          pPrevBarrier = pBarrier, pBarrier = pBarrier->pNext);
444     if (!pBarrier) return FALSE;
446     /* Remove the swap group from barrier's list */
447     if (pPrevBarrier) pPrevBarrier->pNext = pBarrier->pNext;
448     else              SwapBarrierList[barrier] = pBarrier->pNext;
450     /* Free memory */
451     free(pBarrier);
453     return TRUE;
456 static void UpdateSwapBarrierList(GLuint barrier,
457                                   SwapGroupPtr pOldSwap,
458                                   SwapGroupPtr pNewSwap)
460     SwapBarrierPtr  pBarrier;
462     /* If the old swap group is being destroyed, then we need to remove
463      * the swap group from the list entirely */
464     if (!pNewSwap) {
465         UnbindSwapGroupFromBarrier(barrier, pOldSwap);
466         return;
467     }
469     /* Otherwise, find the old swap group in the barrier list and change
470      * it to the new swap group */
471     for (pBarrier = SwapBarrierList[barrier];
472          pBarrier;
473          pBarrier = pBarrier->pNext) {
474         if (pBarrier->pSwap == pOldSwap) {
475             pBarrier->pSwap = pNewSwap;
476             return;
477         }
478     }
481 static Bool SwapBarrierIsReadyToSwap(GLuint barrier)
483     SwapBarrierPtr  pBarrier;
484     Bool            isReady = TRUE;
486     /* The swap barier is ready to swap when swap groups that are bound
487      * to barrier are ready to swap */
488     for (pBarrier = SwapBarrierList[barrier];
489          pBarrier;
490          pBarrier = pBarrier->pNext)
491         isReady &= SwapGroupIsReadyToSwap(pBarrier->pSwap);
493     return isReady;
496 static void SwapSwapBarrier(GLuint barrier)
498     SwapBarrierPtr  pBarrier;
500     /* Swap each group that is a member of this barrier */
501     for (pBarrier = SwapBarrierList[barrier];
502          pBarrier;
503          pBarrier = pBarrier->pNext)
504         SwapSwapGroup(pBarrier->pSwap);
507 int BindSwapBarrierSGIX(DrawablePtr pDraw, int barrier)
509     /* FIXME: Check for errors when pDraw->type != DRAWABLE_WINDOW */
511     if (barrier < 0 || barrier > GLX_MAX_SWAP_BARRIERS)
512         return BadValue;
514     if (pDraw->type == DRAWABLE_WINDOW) {
515         WindowPtr       pWin       = (WindowPtr)pDraw;
516         dmxWinPrivPtr   pWinPriv   = DMX_GET_WINDOW_PRIV(pWin);
517         SwapGroupPtr    pSwapGroup = pWinPriv->swapGroup;
518         SwapGroupPtr    pCur;
520         if (!pSwapGroup) return BadDrawable;
521         if (barrier && pSwapGroup->barrier) return BadValue;
523         /* Update the swap barrier list */
524         if (barrier) {
525             if (!BindSwapGroupToBarrier(barrier, pSwapGroup))
526                 return BadAlloc;
527         } else {
528             if (!UnbindSwapGroupFromBarrier(pSwapGroup->barrier, pSwapGroup))
529                 return BadDrawable;
530         }
532         /* Set the barrier for each member of this swap group */
533         for (pCur = pSwapGroup; pCur; pCur = pCur->pNext)
534             pCur->barrier = barrier;
535     }
537     return Success;