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
, SwapGroupPtr pNewSwap
);
53 /************************************************************************
57 ************************************************************************/
59 typedef struct _SwapGroup
{
69 __GLXclientState
*clState
;
73 SwapSwapGroup(SwapGroupPtr pSwap
)
77 /* All drawables in swap group are ready to swap, so just swap all
78 * drawables buffers and then wake up those clients that were
79 * previously sleeping */
81 for (pCur
= pSwap
; pCur
; pCur
= pCur
->pNext
) {
83 /* Swap pCur's buffers */
84 __glXDoSwapBuffers(pCur
->clState
, pCur
->drawable
, pCur
->tag
);
85 pCur
->swapping
= FALSE
;
90 ClientWakeup(pCur
->clState
->client
);
91 pCur
->sleeping
= FALSE
;
97 SwapGroupIsReadyToSwap(SwapGroupPtr pSwap
)
101 /* The swap group is ready to swap when all drawables are ready to
102 * swap. NOTE: A drawable is also ready to swap if it is not
103 * currently mapped */
104 for (; pSwap
; pSwap
= pSwap
->pNext
) {
105 isReady
&= (pSwap
->swapping
|| !pSwap
->pWin
->mapped
);
106 /* FIXME: Should we use pSwap->pWin->mapped or ...->realized ??? */
113 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 */
124 SGSwapBuffers(__GLXclientState
* cl
, XID drawId
, GLXContextTag tag
,
127 WindowPtr pWin
= (WindowPtr
) pDraw
;
128 dmxWinPrivPtr pWinPriv
= DMX_GET_WINDOW_PRIV(pWin
);
129 SwapGroupPtr pSwap
= pWinPriv
->swapGroup
;
132 for (pCur
= pSwap
; pCur
&& pCur
->pWin
!= pWin
; pCur
= pCur
->pNext
);
137 pCur
->drawable
= drawId
;
140 /* We are now in the process of swapping */
141 pCur
->swapping
= TRUE
;
143 if (pSwap
->barrier
&& SwapBarrierIsReadyToSwap(pSwap
->barrier
)) {
144 /* The swap group is bound to a barrier and the barrier is ready
145 * to swap, so swap all the swap groups that are bound to this
146 * group's swap barrier */
147 SwapSwapBarrier(pSwap
->barrier
);
149 else if (!pSwap
->barrier
&& SwapGroupIsReadyToSwap(pSwap
)) {
150 /* Do the swap if the entire swap group is ready to swap and the
151 * group is not bound to a swap barrier */
152 SwapSwapGroup(pSwap
);
155 /* The swap group/barrier is not yet ready to swap, so put
156 * client to sleep until the rest are ready to swap */
157 ClientSleep(cl
->client
, SGSwapCleanup
, (pointer
) pWin
);
158 pCur
->sleeping
= TRUE
;
165 SGWindowUnmapped(WindowPtr pWin
)
167 dmxWinPrivPtr pWinPriv
= DMX_GET_WINDOW_PRIV(pWin
);
168 SwapGroupPtr pSwap
= pWinPriv
->swapGroup
;
170 /* Now that one of the windows in the swap group has been unmapped,
171 * see if the entire swap group/barrier is ready to swap */
173 if (pSwap
->barrier
&& SwapBarrierIsReadyToSwap(pSwap
->barrier
)) {
174 SwapSwapBarrier(pSwap
->barrier
);
176 else if (!pSwap
->barrier
&& SwapGroupIsReadyToSwap(pSwap
)) {
177 SwapSwapGroup(pSwap
);
182 SGWindowDestroyed(WindowPtr pWin
)
184 JoinSwapGroupSGIX((DrawablePtr
) pWin
, NULL
);
188 CreateSwapEntry(WindowPtr pWin
)
192 /* Allocate new swap group */
193 pEntry
= malloc(sizeof(*pEntry
));
197 /* Initialize swap group */
199 pEntry
->pNext
= NULL
;
200 pEntry
->swapping
= FALSE
;
201 pEntry
->sleeping
= FALSE
;
203 /* The following are not initialized until SwapBuffers is called:
213 FreeSwapEntry(SwapGroupPtr pEntry
)
215 /* Since we have removed the drawable from its previous swap group
216 * and it won't be added to another swap group, the only thing that
217 * we need to do is to make sure that the drawable's client is not
218 * sleeping. This could happen if one thread is sleeping, while
219 * another thread called glxJoinSwapGroup(). Note that all sleeping
220 * threads should also be swapping, but there is a small window in
221 * the SGSwapBuffer() logic, above, where swapping can be set but
222 * sleeping is not. We check both independently here just to be
225 /* Handle swap buffer request */
226 if (pEntry
->swapping
)
227 __glXDoSwapBuffers(pEntry
->clState
, pEntry
->drawable
, pEntry
->tag
);
230 if (pEntry
->sleeping
)
231 ClientWakeup(pEntry
->clState
->client
);
233 /* We can free the pEntry entry since it has already been removed
234 * from the swap group list and it won't be needed any longer */
239 JoinSwapGroupSGIX(DrawablePtr pDraw
, DrawablePtr pMember
)
241 if (pDraw
->type
== DRAWABLE_WINDOW
) {
242 WindowPtr pWin
= (WindowPtr
) pDraw
;
243 dmxWinPrivPtr pWinPriv
= DMX_GET_WINDOW_PRIV(pWin
);
244 SwapGroupPtr pOldSwap
= NULL
;
247 /* If pDraw and pMember are already members of the same swap
248 * group, just return Success since there is nothing to do */
249 for (pEntry
= pWinPriv
->swapGroup
; pEntry
; pEntry
= pEntry
->pNext
)
250 if (pEntry
->pWin
== (WindowPtr
) pMember
)
253 /* Remove pDraw from its current swap group */
254 if (pWinPriv
->swapGroup
) {
255 SwapGroupPtr pSwapGroup
= pWinPriv
->swapGroup
;
258 /* Find old swap entry in swap group and save in pOldSwap
260 for (pOldSwap
= pWinPriv
->swapGroup
, pPrev
= NULL
;
261 pOldSwap
&& pOldSwap
->pWin
!= pWin
;
262 pPrev
= pOldSwap
, pOldSwap
= pOldSwap
->pNext
);
266 /* Remove pDraw's swap group entry from swap group list */
268 pPrev
->pNext
= pOldSwap
->pNext
;
271 /* pWin is at the head of the swap group list, so we
272 * need to update all other members of this swap
274 for (pEntry
= pOldSwap
->pNext
; pEntry
; pEntry
= pEntry
->pNext
)
275 DMX_GET_WINDOW_PRIV(pEntry
->pWin
)->swapGroup
278 /* Update the barrier list as well */
279 if (pOldSwap
->barrier
)
280 UpdateSwapBarrierList(pOldSwap
->barrier
,
281 pOldSwap
, pOldSwap
->pNext
);
283 /* Set pSwapGroup to point to the swap group without
285 pSwapGroup
= pOldSwap
->pNext
;
288 /* Check to see if current swap group can now swap since we
289 * know at this point that pDraw and pMember are guaranteed
290 * to previously be in different swap groups */
291 if (pSwapGroup
&& SwapGroupIsReadyToSwap(pSwapGroup
)) {
292 SwapSwapGroup(pSwapGroup
);
295 /* Make the old swap entry a standalone group */
296 pOldSwap
->pNext
= NULL
;
297 pOldSwap
->barrier
= 0;
299 /* Reset pWin's swap group */
300 pWinPriv
->swapGroup
= NULL
;
301 pWinPriv
->windowDestroyed
= NULL
;
302 pWinPriv
->windowUnmapped
= NULL
;
305 if (!pMember
|| pMember
->type
!= DRAWABLE_WINDOW
) {
306 /* Free old swap group since it is no longer needed */
308 FreeSwapEntry(pOldSwap
);
310 else if (pDraw
== pMember
&& pOldSwap
) {
311 /* Special case where pDraw was previously created and we
312 * are now just putting it to its own swap group */
313 pWinPriv
->swapGroup
= pOldSwap
;
314 pWinPriv
->windowDestroyed
= SGWindowDestroyed
;
315 pWinPriv
->windowUnmapped
= SGWindowUnmapped
;
317 /* Check to see if pDraw is ready to swap */
318 if (SwapGroupIsReadyToSwap(pOldSwap
))
319 SwapSwapGroup(pOldSwap
);
321 else if (pMember
->type
== DRAWABLE_WINDOW
) {
322 WindowPtr pMemberWin
= (WindowPtr
) pMember
;
323 dmxWinPrivPtr pMemberPriv
= DMX_GET_WINDOW_PRIV(pMemberWin
);
324 SwapGroupPtr pMemberSwapGroup
= pMemberPriv
->swapGroup
;
326 /* Finally, how we can add pDraw to pMember's swap group */
328 /* If pMember is not currently in a swap group, then create
329 * one for it since we are just about to add pDraw to it. */
330 if (!pMemberSwapGroup
) {
331 /* Create new swap group */
332 pMemberSwapGroup
= CreateSwapEntry(pMemberWin
);
333 if (!pMemberSwapGroup
) {
335 FreeSwapEntry(pOldSwap
);
339 /* Set pMember's swap group */
340 pMemberPriv
->swapGroup
= pMemberSwapGroup
;
341 pMemberPriv
->windowDestroyed
= SGWindowDestroyed
;
342 pMemberPriv
->windowUnmapped
= SGWindowUnmapped
;
345 /* If pDraw == pMember, that means pDraw was not a member of
346 * a group previously (or it would have been handled by the
347 * special case above), so no additional work is required
348 * since we just created a new swap group for pMember (i.e.,
351 if (pDraw
!= pMember
) {
352 /* If pDraw was not previously in a swap group, then create
355 /* Create new swap group */
356 pOldSwap
= CreateSwapEntry(pWin
);
358 /* If we just created a swap group for pMember, we
359 * need to free it here */
360 if (pMemberSwapGroup
->pNext
== NULL
) {
361 FreeSwapEntry(pMemberSwapGroup
);
362 pMemberPriv
->swapGroup
= NULL
;
368 /* Find last entry in pMember's swap group */
369 for (pEntry
= pMemberSwapGroup
;
370 pEntry
->pNext
; pEntry
= pEntry
->pNext
);
372 /* Add pDraw's swap group entry to pMember's swap group list */
373 pEntry
->pNext
= pOldSwap
;
375 /* Add pDraw to pMember's swap barrier */
376 pOldSwap
->barrier
= pEntry
->barrier
;
378 /* Set pDraw's swap group */
379 pWinPriv
->swapGroup
= pMemberSwapGroup
;
380 pWinPriv
->windowDestroyed
= SGWindowDestroyed
;
381 pWinPriv
->windowUnmapped
= SGWindowUnmapped
;
389 /************************************************************************
393 ************************************************************************/
395 #define GLX_MAX_SWAP_BARRIERS 10
397 typedef struct _SwapBarrier
*SwapBarrierPtr
;
398 typedef struct _SwapBarrier
{
400 SwapBarrierPtr pNext
;
403 static SwapBarrierPtr SwapBarrierList
[GLX_MAX_SWAP_BARRIERS
+ 1];
406 SwapBarrierInit(void)
410 for (i
= 0; i
<= GLX_MAX_SWAP_BARRIERS
; i
++)
411 SwapBarrierList
[i
] = NULL
;
415 SwapBarrierReset(void)
419 for (i
= 0; i
<= GLX_MAX_SWAP_BARRIERS
; i
++) {
420 SwapBarrierPtr pBarrier
, pNextBarrier
;
422 for (pBarrier
= SwapBarrierList
[i
]; pBarrier
; pBarrier
= pNextBarrier
) {
423 pNextBarrier
= pBarrier
->pNext
;
426 SwapBarrierList
[i
] = NULL
;
431 QueryMaxSwapBarriersSGIX(int screen
)
433 return GLX_MAX_SWAP_BARRIERS
;
437 BindSwapGroupToBarrier(GLuint barrier
, SwapGroupPtr pSwapGroup
)
439 SwapBarrierPtr pBarrier
;
441 pBarrier
= malloc(sizeof(*pBarrier
));
445 /* Add the swap group to barrier's list */
446 pBarrier
->pSwap
= pSwapGroup
;
447 pBarrier
->pNext
= SwapBarrierList
[barrier
];
448 SwapBarrierList
[barrier
] = pBarrier
;
454 UnbindSwapGroupFromBarrier(GLuint barrier
, SwapGroupPtr pSwapGroup
)
456 SwapBarrierPtr pBarrier
, pPrevBarrier
;
458 /* Find the swap group in barrier's list */
459 for (pBarrier
= SwapBarrierList
[barrier
], pPrevBarrier
= NULL
;
460 pBarrier
&& pBarrier
->pSwap
!= pSwapGroup
;
461 pPrevBarrier
= pBarrier
, pBarrier
= pBarrier
->pNext
);
465 /* Remove the swap group from barrier's list */
467 pPrevBarrier
->pNext
= pBarrier
->pNext
;
469 SwapBarrierList
[barrier
] = pBarrier
->pNext
;
478 UpdateSwapBarrierList(GLuint barrier
,
479 SwapGroupPtr pOldSwap
, SwapGroupPtr pNewSwap
)
481 SwapBarrierPtr pBarrier
;
483 /* If the old swap group is being destroyed, then we need to remove
484 * the swap group from the list entirely */
486 UnbindSwapGroupFromBarrier(barrier
, pOldSwap
);
490 /* Otherwise, find the old swap group in the barrier list and change
491 * it to the new swap group */
492 for (pBarrier
= SwapBarrierList
[barrier
];
493 pBarrier
; pBarrier
= pBarrier
->pNext
) {
494 if (pBarrier
->pSwap
== pOldSwap
) {
495 pBarrier
->pSwap
= pNewSwap
;
502 SwapBarrierIsReadyToSwap(GLuint barrier
)
504 SwapBarrierPtr pBarrier
;
507 /* The swap barier is ready to swap when swap groups that are bound
508 * to barrier are ready to swap */
509 for (pBarrier
= SwapBarrierList
[barrier
];
510 pBarrier
; pBarrier
= pBarrier
->pNext
)
511 isReady
&= SwapGroupIsReadyToSwap(pBarrier
->pSwap
);
517 SwapSwapBarrier(GLuint barrier
)
519 SwapBarrierPtr pBarrier
;
521 /* Swap each group that is a member of this barrier */
522 for (pBarrier
= SwapBarrierList
[barrier
];
523 pBarrier
; pBarrier
= pBarrier
->pNext
)
524 SwapSwapGroup(pBarrier
->pSwap
);
528 BindSwapBarrierSGIX(DrawablePtr pDraw
, int barrier
)
530 /* FIXME: Check for errors when pDraw->type != DRAWABLE_WINDOW */
532 if (barrier
< 0 || barrier
> GLX_MAX_SWAP_BARRIERS
)
535 if (pDraw
->type
== DRAWABLE_WINDOW
) {
536 WindowPtr pWin
= (WindowPtr
) pDraw
;
537 dmxWinPrivPtr pWinPriv
= DMX_GET_WINDOW_PRIV(pWin
);
538 SwapGroupPtr pSwapGroup
= pWinPriv
->swapGroup
;
543 if (barrier
&& pSwapGroup
->barrier
)
546 /* Update the swap barrier list */
548 if (!BindSwapGroupToBarrier(barrier
, pSwapGroup
))
552 if (!UnbindSwapGroupFromBarrier(pSwapGroup
->barrier
, pSwapGroup
))
556 /* Set the barrier for each member of this swap group */
557 for (pCur
= pSwapGroup
; pCur
; pCur
= pCur
->pNext
)
558 pCur
->barrier
= barrier
;