Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / dmx / glxProxy / glxswap.c
CommitLineData
a09e091a
JB
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 */
27
28/*
29 * Authors:
30 * Kevin E. Martin <kem@redhat.com>
31 *
32 */
33
34#ifdef HAVE_DMX_CONFIG_H
35#include <dmx-config.h>
36#endif
37
38#include "dmx.h"
39#include "dmxwindow.h"
40#include "glxserver.h"
41#include "glxswap.h"
42
43extern int __glXDoSwapBuffers(__GLXclientState * cl, XID drawId,
44 GLXContextTag tag);
45
46typedef struct _SwapGroup *SwapGroupPtr;
47
48static Bool SwapBarrierIsReadyToSwap(GLuint barrier);
49static void SwapSwapBarrier(GLuint barrier);
50static void UpdateSwapBarrierList(GLuint barrier,
51 SwapGroupPtr pOldSwap, SwapGroupPtr pNewSwap);
52
53/************************************************************************
54 *
55 * Swap Groups
56 *
57 ************************************************************************/
58
59typedef struct _SwapGroup {
60 WindowPtr pWin;
61 SwapGroupPtr pNext;
62
63 Bool swapping;
64 Bool sleeping;
65 GLuint barrier;
66
67 XID drawable;
68 GLXContextTag tag;
69 __GLXclientState *clState;
70} SwapGroupRec;
71
72static void
73SwapSwapGroup(SwapGroupPtr pSwap)
74{
75 SwapGroupPtr pCur;
76
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 */
80
81 for (pCur = pSwap; pCur; pCur = pCur->pNext) {
82 if (pCur->swapping) {
83 /* Swap pCur's buffers */
84 __glXDoSwapBuffers(pCur->clState, pCur->drawable, pCur->tag);
85 pCur->swapping = FALSE;
86 }
87
88 /* Wakeup client */
89 if (pCur->sleeping) {
90 ClientWakeup(pCur->clState->client);
91 pCur->sleeping = FALSE;
92 }
93 }
94}
95
96static Bool
97SwapGroupIsReadyToSwap(SwapGroupPtr pSwap)
98{
99 Bool isReady = TRUE;
100
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 ??? */
107 }
108
109 return isReady;
110}
111
112static Bool
113SGSwapCleanup(ClientPtr client, pointer closure)
114{
115 /* SwapGroupPtr pSwap = (SwapGroupPtr)closure; */
116
117 /* This should not be called unless the client has died in which
118 * case we should remove the buffer from the swap list */
119
120 return TRUE;
121}
122
123int
124SGSwapBuffers(__GLXclientState * cl, XID drawId, GLXContextTag tag,
125 DrawablePtr pDraw)
126{
127 WindowPtr pWin = (WindowPtr) pDraw;
128 dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
129 SwapGroupPtr pSwap = pWinPriv->swapGroup;
130 SwapGroupPtr pCur;
131
132 for (pCur = pSwap; pCur && pCur->pWin != pWin; pCur = pCur->pNext);
133 if (!pCur)
134 return BadDrawable;
135
136 pCur->clState = cl;
137 pCur->drawable = drawId;
138 pCur->tag = tag;
139
140 /* We are now in the process of swapping */
141 pCur->swapping = TRUE;
142
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);
148 }
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);
153 }
154 else {
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;
159 }
160
161 return Success;
162}
163
164static void
165SGWindowUnmapped(WindowPtr pWin)
166{
167 dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
168 SwapGroupPtr pSwap = pWinPriv->swapGroup;
169
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 */
172
173 if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) {
174 SwapSwapBarrier(pSwap->barrier);
175 }
176 else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) {
177 SwapSwapGroup(pSwap);
178 }
179}
180
181static void
182SGWindowDestroyed(WindowPtr pWin)
183{
184 JoinSwapGroupSGIX((DrawablePtr) pWin, NULL);
185}
186
187static SwapGroupPtr
188CreateSwapEntry(WindowPtr pWin)
189{
190 SwapGroupPtr pEntry;
191
192 /* Allocate new swap group */
193 pEntry = malloc(sizeof(*pEntry));
194 if (!pEntry)
195 return NULL;
196
197 /* Initialize swap group */
198 pEntry->pWin = pWin;
199 pEntry->pNext = NULL;
200 pEntry->swapping = FALSE;
201 pEntry->sleeping = FALSE;
202 pEntry->barrier = 0;
203 /* The following are not initialized until SwapBuffers is called:
204 * pEntry->drawable
205 * pEntry->tag
206 * pEntry->clState
207 */
208
209 return pEntry;
210}
211
212static void
213FreeSwapEntry(SwapGroupPtr pEntry)
214{
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
223 * pedantic. */
224
225 /* Handle swap buffer request */
226 if (pEntry->swapping)
227 __glXDoSwapBuffers(pEntry->clState, pEntry->drawable, pEntry->tag);
228
229 /* Wake up client */
230 if (pEntry->sleeping)
231 ClientWakeup(pEntry->clState->client);
232
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 */
235 free(pEntry);
236}
237
238int
239JoinSwapGroupSGIX(DrawablePtr pDraw, DrawablePtr pMember)
240{
241 if (pDraw->type == DRAWABLE_WINDOW) {
242 WindowPtr pWin = (WindowPtr) pDraw;
243 dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
244 SwapGroupPtr pOldSwap = NULL;
245 SwapGroupPtr pEntry;
246
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)
251 return Success;
252
253 /* Remove pDraw from its current swap group */
254 if (pWinPriv->swapGroup) {
255 SwapGroupPtr pSwapGroup = pWinPriv->swapGroup;
256 SwapGroupPtr pPrev;
257
258 /* Find old swap entry in swap group and save in pOldSwap
259 * for later use */
260 for (pOldSwap = pWinPriv->swapGroup, pPrev = NULL;
261 pOldSwap && pOldSwap->pWin != pWin;
262 pPrev = pOldSwap, pOldSwap = pOldSwap->pNext);
263 if (!pOldSwap)
264 return BadDrawable;
265
266 /* Remove pDraw's swap group entry from swap group list */
267 if (pPrev) {
268 pPrev->pNext = pOldSwap->pNext;
269 }
270 else {
271 /* pWin is at the head of the swap group list, so we
272 * need to update all other members of this swap
273 * group */
274 for (pEntry = pOldSwap->pNext; pEntry; pEntry = pEntry->pNext)
275 DMX_GET_WINDOW_PRIV(pEntry->pWin)->swapGroup
276 = pOldSwap->pNext;
277
278 /* Update the barrier list as well */
279 if (pOldSwap->barrier)
280 UpdateSwapBarrierList(pOldSwap->barrier,
281 pOldSwap, pOldSwap->pNext);
282
283 /* Set pSwapGroup to point to the swap group without
284 * pOldSwap */
285 pSwapGroup = pOldSwap->pNext;
286 }
287
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);
293 }
294
295 /* Make the old swap entry a standalone group */
296 pOldSwap->pNext = NULL;
297 pOldSwap->barrier = 0;
298
299 /* Reset pWin's swap group */
300 pWinPriv->swapGroup = NULL;
301 pWinPriv->windowDestroyed = NULL;
302 pWinPriv->windowUnmapped = NULL;
303 }
304
305 if (!pMember || pMember->type != DRAWABLE_WINDOW) {
306 /* Free old swap group since it is no longer needed */
307 if (pOldSwap)
308 FreeSwapEntry(pOldSwap);
309 }
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;
316
317 /* Check to see if pDraw is ready to swap */
318 if (SwapGroupIsReadyToSwap(pOldSwap))
319 SwapSwapGroup(pOldSwap);
320 }
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;
325
326 /* Finally, how we can add pDraw to pMember's swap group */
327
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) {
334 if (pOldSwap)
335 FreeSwapEntry(pOldSwap);
336 return BadAlloc;
337 }
338
339 /* Set pMember's swap group */
340 pMemberPriv->swapGroup = pMemberSwapGroup;
341 pMemberPriv->windowDestroyed = SGWindowDestroyed;
342 pMemberPriv->windowUnmapped = SGWindowUnmapped;
343 }
344
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.,
349 * pDraw). */
350
351 if (pDraw != pMember) {
352 /* If pDraw was not previously in a swap group, then create
353 * an entry for it */
354 if (!pOldSwap) {
355 /* Create new swap group */
356 pOldSwap = CreateSwapEntry(pWin);
357 if (!pOldSwap) {
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;
363 }
364 return BadAlloc;
365 }
366 }
367
368 /* Find last entry in pMember's swap group */
369 for (pEntry = pMemberSwapGroup;
370 pEntry->pNext; pEntry = pEntry->pNext);
371
372 /* Add pDraw's swap group entry to pMember's swap group list */
373 pEntry->pNext = pOldSwap;
374
375 /* Add pDraw to pMember's swap barrier */
376 pOldSwap->barrier = pEntry->barrier;
377
378 /* Set pDraw's swap group */
379 pWinPriv->swapGroup = pMemberSwapGroup;
380 pWinPriv->windowDestroyed = SGWindowDestroyed;
381 pWinPriv->windowUnmapped = SGWindowUnmapped;
382 }
383 }
384 }
385
386 return Success;
387}
388
389/************************************************************************
390 *
391 * Swap Barriers
392 *
393 ************************************************************************/
394
395#define GLX_MAX_SWAP_BARRIERS 10
396
397typedef struct _SwapBarrier *SwapBarrierPtr;
398typedef struct _SwapBarrier {
399 SwapGroupPtr pSwap;
400 SwapBarrierPtr pNext;
401} SwapBarrierRec;
402
403static SwapBarrierPtr SwapBarrierList[GLX_MAX_SWAP_BARRIERS + 1];
404
405void
406SwapBarrierInit(void)
407{
408 int i;
409
410 for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++)
411 SwapBarrierList[i] = NULL;
412}
413
414void
415SwapBarrierReset(void)
416{
417 int i;
418
419 for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) {
420 SwapBarrierPtr pBarrier, pNextBarrier;
421
422 for (pBarrier = SwapBarrierList[i]; pBarrier; pBarrier = pNextBarrier) {
423 pNextBarrier = pBarrier->pNext;
424 free(pBarrier);
425 }
426 SwapBarrierList[i] = NULL;
427 }
428}
429
430int
431QueryMaxSwapBarriersSGIX(int screen)
432{
433 return GLX_MAX_SWAP_BARRIERS;
434}
435
436static Bool
437BindSwapGroupToBarrier(GLuint barrier, SwapGroupPtr pSwapGroup)
438{
439 SwapBarrierPtr pBarrier;
440
441 pBarrier = malloc(sizeof(*pBarrier));
442 if (!pBarrier)
443 return FALSE;
444
445 /* Add the swap group to barrier's list */
446 pBarrier->pSwap = pSwapGroup;
447 pBarrier->pNext = SwapBarrierList[barrier];
448 SwapBarrierList[barrier] = pBarrier;
449
450 return TRUE;
451}
452
453static Bool
454UnbindSwapGroupFromBarrier(GLuint barrier, SwapGroupPtr pSwapGroup)
455{
456 SwapBarrierPtr pBarrier, pPrevBarrier;
457
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);
462 if (!pBarrier)
463 return FALSE;
464
465 /* Remove the swap group from barrier's list */
466 if (pPrevBarrier)
467 pPrevBarrier->pNext = pBarrier->pNext;
468 else
469 SwapBarrierList[barrier] = pBarrier->pNext;
470
471 /* Free memory */
472 free(pBarrier);
473
474 return TRUE;
475}
476
477static void
478UpdateSwapBarrierList(GLuint barrier,
479 SwapGroupPtr pOldSwap, SwapGroupPtr pNewSwap)
480{
481 SwapBarrierPtr pBarrier;
482
483 /* If the old swap group is being destroyed, then we need to remove
484 * the swap group from the list entirely */
485 if (!pNewSwap) {
486 UnbindSwapGroupFromBarrier(barrier, pOldSwap);
487 return;
488 }
489
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;
496 return;
497 }
498 }
499}
500
501static Bool
502SwapBarrierIsReadyToSwap(GLuint barrier)
503{
504 SwapBarrierPtr pBarrier;
505 Bool isReady = TRUE;
506
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);
512
513 return isReady;
514}
515
516static void
517SwapSwapBarrier(GLuint barrier)
518{
519 SwapBarrierPtr pBarrier;
520
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);
525}
526
527int
528BindSwapBarrierSGIX(DrawablePtr pDraw, int barrier)
529{
530 /* FIXME: Check for errors when pDraw->type != DRAWABLE_WINDOW */
531
532 if (barrier < 0 || barrier > GLX_MAX_SWAP_BARRIERS)
533 return BadValue;
534
535 if (pDraw->type == DRAWABLE_WINDOW) {
536 WindowPtr pWin = (WindowPtr) pDraw;
537 dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
538 SwapGroupPtr pSwapGroup = pWinPriv->swapGroup;
539 SwapGroupPtr pCur;
540
541 if (!pSwapGroup)
542 return BadDrawable;
543 if (barrier && pSwapGroup->barrier)
544 return BadValue;
545
546 /* Update the swap barrier list */
547 if (barrier) {
548 if (!BindSwapGroupToBarrier(barrier, pSwapGroup))
549 return BadAlloc;
550 }
551 else {
552 if (!UnbindSwapGroupFromBarrier(pSwapGroup->barrier, pSwapGroup))
553 return BadDrawable;
554 }
555
556 /* Set the barrier for each member of this swap group */
557 for (pCur = pSwapGroup; pCur; pCur = pCur->pNext)
558 pCur->barrier = barrier;
559 }
560
561 return Success;
562}