First import
[xorg_rtime.git] / xorg-server-1.4 / hw / dmx / glxProxy / glxswap.c
blob8fa04f8778a1f8d6426f4e9bd61e3e54c220c71b
1 /*
2 * Copyright 2003 Red Hat Inc., Raleigh, North Carolina.
4 * All Rights Reserved.
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
25 * SOFTWARE.
29 * Authors:
30 * Kevin E. Martin <kem@redhat.com>
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 /************************************************************************
57 * Swap Groups
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)
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;
90 /* Wakeup client */
91 if (pCur->sleeping) {
92 ClientWakeup(pCur->clState->client);
93 pCur->sleeping = FALSE;
98 static Bool SwapGroupIsReadyToSwap(SwapGroupPtr pSwap)
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 ??? */
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;
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);
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 = xalloc(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
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 xfree(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;
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);
321 return BadAlloc;
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.,
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;
349 return BadAlloc;
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;
372 return Success;
376 /************************************************************************
378 * Swap Barriers
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 xfree(pBarrier);
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;
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 xfree(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;
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;
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;
532 /* Set the barrier for each member of this swap group */
533 for (pCur = pSwapGroup; pCur; pCur = pCur->pNext)
534 pCur->barrier = barrier;
537 return Success;