2 * Copyright 2003 Red Hat Inc., Raleigh, North Carolina.
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:
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.
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
30 * Kevin E. Martin <kem@redhat.com>
34 #ifdef HAVE_DMX_CONFIG_H
35 #include <dmx-config.h>
39 #include "dmxwindow.h"
40 #include "glxserver.h"
43 extern int __glXDoSwapBuffers(__GLXclientState
*cl
, XID drawId
,
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 /************************************************************************
59 ************************************************************************/
61 typedef struct _SwapGroup
{
71 __GLXclientState
*clState
;
75 static void SwapSwapGroup(SwapGroupPtr pSwap
)
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
) {
85 /* Swap pCur's buffers */
86 __glXDoSwapBuffers(pCur
->clState
, pCur
->drawable
, pCur
->tag
);
87 pCur
->swapping
= FALSE
;
92 ClientWakeup(pCur
->clState
->client
);
93 pCur
->sleeping
= FALSE
;
98 static Bool
SwapGroupIsReadyToSwap(SwapGroupPtr pSwap
)
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 ??? */
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 */
123 int SGSwapBuffers(__GLXclientState
*cl
, XID drawId
, GLXContextTag tag
,
126 WindowPtr pWin
= (WindowPtr
)pDraw
;
127 dmxWinPrivPtr pWinPriv
= DMX_GET_WINDOW_PRIV(pWin
);
128 SwapGroupPtr pSwap
= pWinPriv
->swapGroup
;
131 for (pCur
= pSwap
; pCur
&& pCur
->pWin
!= pWin
; pCur
= pCur
->pNext
);
136 pCur
->drawable
= drawId
;
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
);
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
;
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
);
176 static void SGWindowDestroyed(WindowPtr pWin
)
178 JoinSwapGroupSGIX((DrawablePtr
)pWin
, NULL
);
181 static SwapGroupPtr
CreateSwapEntry(WindowPtr pWin
)
185 /* Allocate new swap group */
186 pEntry
= xalloc(sizeof(*pEntry
));
187 if (!pEntry
) return NULL
;
189 /* Initialize swap group */
191 pEntry
->pNext
= NULL
;
192 pEntry
->swapping
= FALSE
;
193 pEntry
->sleeping
= FALSE
;
195 /* The following are not initialized until SwapBuffers is called:
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
216 /* Handle swap buffer request */
217 if (pEntry
->swapping
)
218 __glXDoSwapBuffers(pEntry
->clState
, pEntry
->drawable
, pEntry
->tag
);
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 */
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
;
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
)
243 /* Remove pDraw from its current swap group */
244 if (pWinPriv
->swapGroup
) {
245 SwapGroupPtr pSwapGroup
= pWinPriv
->swapGroup
;
248 /* Find old swap entry in swap group and save in pOldSwap
250 for (pOldSwap
= pWinPriv
->swapGroup
, pPrev
= NULL
;
251 pOldSwap
&& pOldSwap
->pWin
!= pWin
;
252 pPrev
= pOldSwap
, pOldSwap
= pOldSwap
->pNext
);
256 /* Remove pDraw's swap group entry from swap group list */
258 pPrev
->pNext
= pOldSwap
->pNext
;
260 /* pWin is at the head of the swap group list, so we
261 * need to update all other members of this swap
263 for (pEntry
= pOldSwap
->pNext
; pEntry
; pEntry
= pEntry
->pNext
)
264 DMX_GET_WINDOW_PRIV(pEntry
->pWin
)->swapGroup
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
274 pSwapGroup
= pOldSwap
->pNext
;
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
);
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
;
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
);
324 /* Set pMember's swap group */
325 pMemberPriv
->swapGroup
= pMemberSwapGroup
;
326 pMemberPriv
->windowDestroyed
= SGWindowDestroyed
;
327 pMemberPriv
->windowUnmapped
= SGWindowUnmapped
;
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.,
336 if (pDraw
!= pMember
) {
337 /* If pDraw was not previously in a swap group, then create
340 /* Create new swap group */
341 pOldSwap
= CreateSwapEntry(pWin
);
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
;
353 /* Find last entry in pMember's swap group */
354 for (pEntry
= pMemberSwapGroup
;
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
;
376 /************************************************************************
380 ************************************************************************/
382 #define GLX_MAX_SWAP_BARRIERS 10
384 typedef struct _SwapBarrier
*SwapBarrierPtr
;
385 typedef struct _SwapBarrier
{
387 SwapBarrierPtr pNext
;
390 static SwapBarrierPtr SwapBarrierList
[GLX_MAX_SWAP_BARRIERS
+1];
392 void SwapBarrierInit(void)
396 for (i
= 0; i
<= GLX_MAX_SWAP_BARRIERS
; i
++)
397 SwapBarrierList
[i
] = NULL
;
400 void SwapBarrierReset(void)
404 for (i
= 0; i
<= GLX_MAX_SWAP_BARRIERS
; i
++) {
405 SwapBarrierPtr pBarrier
, pNextBarrier
;;
406 for (pBarrier
= SwapBarrierList
[i
];
408 pBarrier
= pNextBarrier
) {
409 pNextBarrier
= pBarrier
->pNext
;
412 SwapBarrierList
[i
] = NULL
;
416 int QueryMaxSwapBarriersSGIX(int screen
)
418 return GLX_MAX_SWAP_BARRIERS
;
421 static Bool
BindSwapGroupToBarrier(GLuint barrier
, SwapGroupPtr pSwapGroup
)
423 SwapBarrierPtr pBarrier
;
425 pBarrier
= xalloc(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
;
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
;
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 */
465 UnbindSwapGroupFromBarrier(barrier
, pOldSwap
);
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
];
473 pBarrier
= pBarrier
->pNext
) {
474 if (pBarrier
->pSwap
== pOldSwap
) {
475 pBarrier
->pSwap
= pNewSwap
;
481 static Bool
SwapBarrierIsReadyToSwap(GLuint barrier
)
483 SwapBarrierPtr pBarrier
;
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
];
490 pBarrier
= pBarrier
->pNext
)
491 isReady
&= SwapGroupIsReadyToSwap(pBarrier
->pSwap
);
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
];
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
)
514 if (pDraw
->type
== DRAWABLE_WINDOW
) {
515 WindowPtr pWin
= (WindowPtr
)pDraw
;
516 dmxWinPrivPtr pWinPriv
= DMX_GET_WINDOW_PRIV(pWin
);
517 SwapGroupPtr pSwapGroup
= pWinPriv
->swapGroup
;
520 if (!pSwapGroup
) return BadDrawable
;
521 if (barrier
&& pSwapGroup
->barrier
) return BadValue
;
523 /* Update the swap barrier list */
525 if (!BindSwapGroupToBarrier(barrier
, pSwapGroup
))
528 if (!UnbindSwapGroupFromBarrier(pSwapGroup
->barrier
, pSwapGroup
))
532 /* Set the barrier for each member of this swap group */
533 for (pCur
= pSwapGroup
; pCur
; pCur
= pCur
->pNext
)
534 pCur
->barrier
= barrier
;