xref: /OK3568_Linux_fs/external/xserver/hw/dmx/glxProxy/glxswap.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 #include "glxcmds.h"
43 
44 typedef struct _SwapGroup *SwapGroupPtr;
45 
46 static Bool SwapBarrierIsReadyToSwap(GLuint barrier);
47 static void SwapSwapBarrier(GLuint barrier);
48 static void UpdateSwapBarrierList(GLuint barrier,
49                                   SwapGroupPtr pOldSwap, SwapGroupPtr pNewSwap);
50 
51 /************************************************************************
52  *
53  * Swap Groups
54  *
55  ************************************************************************/
56 
57 typedef struct _SwapGroup {
58     WindowPtr pWin;
59     SwapGroupPtr pNext;
60 
61     Bool swapping;
62     Bool sleeping;
63     GLuint barrier;
64 
65     XID drawable;
66     GLXContextTag tag;
67     __GLXclientState *clState;
68 } SwapGroupRec;
69 
70 static void
SwapSwapGroup(SwapGroupPtr pSwap)71 SwapSwapGroup(SwapGroupPtr pSwap)
72 {
73     SwapGroupPtr pCur;
74 
75     /* All drawables in swap group are ready to swap, so just swap all
76      * drawables buffers and then wake up those clients that were
77      * previously sleeping */
78 
79     for (pCur = pSwap; pCur; pCur = pCur->pNext) {
80         if (pCur->swapping) {
81             /* Swap pCur's buffers */
82             __glXDoSwapBuffers(pCur->clState, pCur->drawable, pCur->tag);
83             pCur->swapping = FALSE;
84         }
85 
86         /* Wakeup client */
87         if (pCur->sleeping) {
88             ClientWakeup(pCur->clState->client);
89             pCur->sleeping = FALSE;
90         }
91     }
92 }
93 
94 static Bool
SwapGroupIsReadyToSwap(SwapGroupPtr pSwap)95 SwapGroupIsReadyToSwap(SwapGroupPtr pSwap)
96 {
97     Bool isReady = TRUE;
98 
99     /* The swap group is ready to swap when all drawables are ready to
100      * swap.  NOTE: A drawable is also ready to swap if it is not
101      * currently mapped */
102     for (; pSwap; pSwap = pSwap->pNext) {
103         isReady &= (pSwap->swapping || !pSwap->pWin->mapped);
104         /* FIXME: Should we use pSwap->pWin->mapped or ...->realized ??? */
105     }
106 
107     return isReady;
108 }
109 
110 static Bool
SGSwapCleanup(ClientPtr client,void * closure)111 SGSwapCleanup(ClientPtr client, void *closure)
112 {
113     /* SwapGroupPtr  pSwap = (SwapGroupPtr)closure; */
114 
115     /* This should not be called unless the client has died in which
116      * case we should remove the buffer from the swap list */
117 
118     return TRUE;
119 }
120 
121 int
SGSwapBuffers(__GLXclientState * cl,XID drawId,GLXContextTag tag,DrawablePtr pDraw)122 SGSwapBuffers(__GLXclientState * cl, XID drawId, GLXContextTag tag,
123               DrawablePtr pDraw)
124 {
125     WindowPtr pWin = (WindowPtr) pDraw;
126     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
127     SwapGroupPtr pSwap = pWinPriv->swapGroup;
128     SwapGroupPtr pCur;
129 
130     for (pCur = pSwap; pCur && pCur->pWin != pWin; pCur = pCur->pNext);
131     if (!pCur)
132         return BadDrawable;
133 
134     pCur->clState = cl;
135     pCur->drawable = drawId;
136     pCur->tag = tag;
137 
138     /* We are now in the process of swapping */
139     pCur->swapping = TRUE;
140 
141     if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) {
142         /* The swap group is bound to a barrier and the barrier is ready
143          * to swap, so swap all the swap groups that are bound to this
144          * group's swap barrier */
145         SwapSwapBarrier(pSwap->barrier);
146     }
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     }
152     else {
153         /* The swap group/barrier is not yet ready to swap, so put
154          * client to sleep until the rest are ready to swap */
155         ClientSleep(cl->client, SGSwapCleanup, (void *) pWin);
156         pCur->sleeping = TRUE;
157     }
158 
159     return Success;
160 }
161 
162 static void
SGWindowUnmapped(WindowPtr pWin)163 SGWindowUnmapped(WindowPtr pWin)
164 {
165     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
166     SwapGroupPtr pSwap = pWinPriv->swapGroup;
167 
168     /* Now that one of the windows in the swap group has been unmapped,
169      * see if the entire swap group/barrier is ready to swap */
170 
171     if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) {
172         SwapSwapBarrier(pSwap->barrier);
173     }
174     else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) {
175         SwapSwapGroup(pSwap);
176     }
177 }
178 
179 static void
SGWindowDestroyed(WindowPtr pWin)180 SGWindowDestroyed(WindowPtr pWin)
181 {
182     JoinSwapGroupSGIX((DrawablePtr) pWin, NULL);
183 }
184 
185 static SwapGroupPtr
CreateSwapEntry(WindowPtr pWin)186 CreateSwapEntry(WindowPtr pWin)
187 {
188     SwapGroupPtr pEntry;
189 
190     /* Allocate new swap group */
191     pEntry = malloc(sizeof(*pEntry));
192     if (!pEntry)
193         return NULL;
194 
195     /* Initialize swap group */
196     pEntry->pWin = pWin;
197     pEntry->pNext = NULL;
198     pEntry->swapping = FALSE;
199     pEntry->sleeping = FALSE;
200     pEntry->barrier = 0;
201     /* The following are not initialized until SwapBuffers is called:
202      *     pEntry->drawable
203      *     pEntry->tag
204      *     pEntry->clState
205      */
206 
207     return pEntry;
208 }
209 
210 static void
FreeSwapEntry(SwapGroupPtr pEntry)211 FreeSwapEntry(SwapGroupPtr pEntry)
212 {
213     /* Since we have removed the drawable from its previous swap group
214      * and it won't be added to another swap group, the only thing that
215      * we need to do is to make sure that the drawable's client is not
216      * sleeping.  This could happen if one thread is sleeping, while
217      * another thread called glxJoinSwapGroup().  Note that all sleeping
218      * threads should also be swapping, but there is a small window in
219      * the SGSwapBuffer() logic, above, where swapping can be set but
220      * sleeping is not.  We check both independently here just to be
221      * pedantic. */
222 
223     /* Handle swap buffer request */
224     if (pEntry->swapping)
225         __glXDoSwapBuffers(pEntry->clState, pEntry->drawable, pEntry->tag);
226 
227     /* Wake up client */
228     if (pEntry->sleeping)
229         ClientWakeup(pEntry->clState->client);
230 
231     /* We can free the pEntry entry since it has already been removed
232      * from the swap group list and it won't be needed any longer */
233     free(pEntry);
234 }
235 
236 int
JoinSwapGroupSGIX(DrawablePtr pDraw,DrawablePtr pMember)237 JoinSwapGroupSGIX(DrawablePtr pDraw, DrawablePtr pMember)
238 {
239     if (pDraw->type == DRAWABLE_WINDOW) {
240         WindowPtr pWin = (WindowPtr) pDraw;
241         dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
242         SwapGroupPtr pOldSwap = NULL;
243         SwapGroupPtr pEntry;
244 
245         /* If pDraw and pMember are already members of the same swap
246          * group, just return Success since there is nothing to do */
247         for (pEntry = pWinPriv->swapGroup; pEntry; pEntry = pEntry->pNext)
248             if (pEntry->pWin == (WindowPtr) pMember)
249                 return Success;
250 
251         /* Remove pDraw from its current swap group */
252         if (pWinPriv->swapGroup) {
253             SwapGroupPtr pSwapGroup = pWinPriv->swapGroup;
254             SwapGroupPtr pPrev;
255 
256             /* Find old swap entry in swap group and save in pOldSwap
257              * for later use */
258             for (pOldSwap = pWinPriv->swapGroup, pPrev = NULL;
259                  pOldSwap && pOldSwap->pWin != pWin;
260                  pPrev = pOldSwap, pOldSwap = pOldSwap->pNext);
261             if (!pOldSwap)
262                 return BadDrawable;
263 
264             /* Remove pDraw's swap group entry from swap group list */
265             if (pPrev) {
266                 pPrev->pNext = pOldSwap->pNext;
267             }
268             else {
269                 /* pWin is at the head of the swap group list, so we
270                  * need to update all other members of this swap
271                  * group */
272                 for (pEntry = pOldSwap->pNext; pEntry; pEntry = pEntry->pNext)
273                     DMX_GET_WINDOW_PRIV(pEntry->pWin)->swapGroup
274                         = pOldSwap->pNext;
275 
276                 /* Update the barrier list as well */
277                 if (pOldSwap->barrier)
278                     UpdateSwapBarrierList(pOldSwap->barrier,
279                                           pOldSwap, pOldSwap->pNext);
280 
281                 /* Set pSwapGroup to point to the swap group without
282                  * pOldSwap */
283                 pSwapGroup = pOldSwap->pNext;
284             }
285 
286             /* Check to see if current swap group can now swap since we
287              * know at this point that pDraw and pMember are guaranteed
288              * to previously be in different swap groups */
289             if (pSwapGroup && SwapGroupIsReadyToSwap(pSwapGroup)) {
290                 SwapSwapGroup(pSwapGroup);
291             }
292 
293             /* Make the old swap entry a standalone group */
294             pOldSwap->pNext = NULL;
295             pOldSwap->barrier = 0;
296 
297             /* Reset pWin's swap group */
298             pWinPriv->swapGroup = NULL;
299             pWinPriv->windowDestroyed = NULL;
300             pWinPriv->windowUnmapped = NULL;
301         }
302 
303         if (!pMember || pMember->type != DRAWABLE_WINDOW) {
304             /* Free old swap group since it is no longer needed */
305             if (pOldSwap)
306                 FreeSwapEntry(pOldSwap);
307         }
308         else if (pDraw == pMember && pOldSwap) {
309             /* Special case where pDraw was previously created and we
310              * are now just putting it to its own swap group */
311             pWinPriv->swapGroup = pOldSwap;
312             pWinPriv->windowDestroyed = SGWindowDestroyed;
313             pWinPriv->windowUnmapped = SGWindowUnmapped;
314 
315             /* Check to see if pDraw is ready to swap */
316             if (SwapGroupIsReadyToSwap(pOldSwap))
317                 SwapSwapGroup(pOldSwap);
318         }
319         else if (pMember->type == DRAWABLE_WINDOW) {
320             WindowPtr pMemberWin = (WindowPtr) pMember;
321             dmxWinPrivPtr pMemberPriv = DMX_GET_WINDOW_PRIV(pMemberWin);
322             SwapGroupPtr pMemberSwapGroup = pMemberPriv->swapGroup;
323 
324             /* Finally, how we can add pDraw to pMember's swap group */
325 
326             /* If pMember is not currently in a swap group, then create
327              * one for it since we are just about to add pDraw to it. */
328             if (!pMemberSwapGroup) {
329                 /* Create new swap group */
330                 pMemberSwapGroup = CreateSwapEntry(pMemberWin);
331                 if (!pMemberSwapGroup) {
332                     if (pOldSwap)
333                         FreeSwapEntry(pOldSwap);
334                     return BadAlloc;
335                 }
336 
337                 /* Set pMember's swap group */
338                 pMemberPriv->swapGroup = pMemberSwapGroup;
339                 pMemberPriv->windowDestroyed = SGWindowDestroyed;
340                 pMemberPriv->windowUnmapped = SGWindowUnmapped;
341             }
342 
343             /* If pDraw == pMember, that means pDraw was not a member of
344              * a group previously (or it would have been handled by the
345              * special case above), so no additional work is required
346              * since we just created a new swap group for pMember (i.e.,
347              * pDraw). */
348 
349             if (pDraw != pMember) {
350                 /* If pDraw was not previously in a swap group, then create
351                  * an entry for it */
352                 if (!pOldSwap) {
353                     /* Create new swap group */
354                     pOldSwap = CreateSwapEntry(pWin);
355                     if (!pOldSwap) {
356                         /* If we just created a swap group for pMember, we
357                          * need to free it here */
358                         if (pMemberSwapGroup->pNext == NULL) {
359                             FreeSwapEntry(pMemberSwapGroup);
360                             pMemberPriv->swapGroup = NULL;
361                         }
362                         return BadAlloc;
363                     }
364                 }
365 
366                 /* Find last entry in pMember's swap group */
367                 for (pEntry = pMemberSwapGroup;
368                      pEntry->pNext; pEntry = pEntry->pNext);
369 
370                 /* Add pDraw's swap group entry to pMember's swap group list */
371                 pEntry->pNext = pOldSwap;
372 
373                 /* Add pDraw to pMember's swap barrier */
374                 pOldSwap->barrier = pEntry->barrier;
375 
376                 /* Set pDraw's swap group */
377                 pWinPriv->swapGroup = pMemberSwapGroup;
378                 pWinPriv->windowDestroyed = SGWindowDestroyed;
379                 pWinPriv->windowUnmapped = SGWindowUnmapped;
380             }
381         }
382     }
383 
384     return Success;
385 }
386 
387 /************************************************************************
388  *
389  * Swap Barriers
390  *
391  ************************************************************************/
392 
393 #define GLX_MAX_SWAP_BARRIERS 10
394 
395 typedef struct _SwapBarrier *SwapBarrierPtr;
396 typedef struct _SwapBarrier {
397     SwapGroupPtr pSwap;
398     SwapBarrierPtr pNext;
399 } SwapBarrierRec;
400 
401 static SwapBarrierPtr SwapBarrierList[GLX_MAX_SWAP_BARRIERS + 1];
402 
403 void
SwapBarrierInit(void)404 SwapBarrierInit(void)
405 {
406     int i;
407 
408     for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++)
409         SwapBarrierList[i] = NULL;
410 }
411 
412 void
SwapBarrierReset(void)413 SwapBarrierReset(void)
414 {
415     int i;
416 
417     for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) {
418         SwapBarrierPtr pBarrier, pNextBarrier;
419 
420         for (pBarrier = SwapBarrierList[i]; pBarrier; pBarrier = pNextBarrier) {
421             pNextBarrier = pBarrier->pNext;
422             free(pBarrier);
423         }
424         SwapBarrierList[i] = NULL;
425     }
426 }
427 
428 int
QueryMaxSwapBarriersSGIX(int screen)429 QueryMaxSwapBarriersSGIX(int screen)
430 {
431     return GLX_MAX_SWAP_BARRIERS;
432 }
433 
434 static Bool
BindSwapGroupToBarrier(GLuint barrier,SwapGroupPtr pSwapGroup)435 BindSwapGroupToBarrier(GLuint barrier, SwapGroupPtr pSwapGroup)
436 {
437     SwapBarrierPtr pBarrier;
438 
439     pBarrier = malloc(sizeof(*pBarrier));
440     if (!pBarrier)
441         return FALSE;
442 
443     /* Add the swap group to barrier's list */
444     pBarrier->pSwap = pSwapGroup;
445     pBarrier->pNext = SwapBarrierList[barrier];
446     SwapBarrierList[barrier] = pBarrier;
447 
448     return TRUE;
449 }
450 
451 static Bool
UnbindSwapGroupFromBarrier(GLuint barrier,SwapGroupPtr pSwapGroup)452 UnbindSwapGroupFromBarrier(GLuint barrier, SwapGroupPtr pSwapGroup)
453 {
454     SwapBarrierPtr pBarrier, pPrevBarrier;
455 
456     /* Find the swap group in barrier's list */
457     for (pBarrier = SwapBarrierList[barrier], pPrevBarrier = NULL;
458          pBarrier && pBarrier->pSwap != pSwapGroup;
459          pPrevBarrier = pBarrier, pBarrier = pBarrier->pNext);
460     if (!pBarrier)
461         return FALSE;
462 
463     /* Remove the swap group from barrier's list */
464     if (pPrevBarrier)
465         pPrevBarrier->pNext = pBarrier->pNext;
466     else
467         SwapBarrierList[barrier] = pBarrier->pNext;
468 
469     /* Free memory */
470     free(pBarrier);
471 
472     return TRUE;
473 }
474 
475 static void
UpdateSwapBarrierList(GLuint barrier,SwapGroupPtr pOldSwap,SwapGroupPtr pNewSwap)476 UpdateSwapBarrierList(GLuint barrier,
477                       SwapGroupPtr pOldSwap, SwapGroupPtr pNewSwap)
478 {
479     SwapBarrierPtr pBarrier;
480 
481     /* If the old swap group is being destroyed, then we need to remove
482      * the swap group from the list entirely */
483     if (!pNewSwap) {
484         UnbindSwapGroupFromBarrier(barrier, pOldSwap);
485         return;
486     }
487 
488     /* Otherwise, find the old swap group in the barrier list and change
489      * it to the new swap group */
490     for (pBarrier = SwapBarrierList[barrier];
491          pBarrier; pBarrier = pBarrier->pNext) {
492         if (pBarrier->pSwap == pOldSwap) {
493             pBarrier->pSwap = pNewSwap;
494             return;
495         }
496     }
497 }
498 
499 static Bool
SwapBarrierIsReadyToSwap(GLuint barrier)500 SwapBarrierIsReadyToSwap(GLuint barrier)
501 {
502     SwapBarrierPtr pBarrier;
503     Bool isReady = TRUE;
504 
505     /* The swap barier is ready to swap when swap groups that are bound
506      * to barrier are ready to swap */
507     for (pBarrier = SwapBarrierList[barrier];
508          pBarrier; pBarrier = pBarrier->pNext)
509         isReady &= SwapGroupIsReadyToSwap(pBarrier->pSwap);
510 
511     return isReady;
512 }
513 
514 static void
SwapSwapBarrier(GLuint barrier)515 SwapSwapBarrier(GLuint barrier)
516 {
517     SwapBarrierPtr pBarrier;
518 
519     /* Swap each group that is a member of this barrier */
520     for (pBarrier = SwapBarrierList[barrier];
521          pBarrier; pBarrier = pBarrier->pNext)
522         SwapSwapGroup(pBarrier->pSwap);
523 }
524 
525 int
BindSwapBarrierSGIX(DrawablePtr pDraw,int barrier)526 BindSwapBarrierSGIX(DrawablePtr pDraw, int barrier)
527 {
528     /* FIXME: Check for errors when pDraw->type != DRAWABLE_WINDOW */
529 
530     if (barrier < 0 || barrier > GLX_MAX_SWAP_BARRIERS)
531         return BadValue;
532 
533     if (pDraw->type == DRAWABLE_WINDOW) {
534         WindowPtr pWin = (WindowPtr) pDraw;
535         dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
536         SwapGroupPtr pSwapGroup = pWinPriv->swapGroup;
537         SwapGroupPtr pCur;
538 
539         if (!pSwapGroup)
540             return BadDrawable;
541         if (barrier && pSwapGroup->barrier)
542             return BadValue;
543 
544         /* Update the swap barrier list */
545         if (barrier) {
546             if (!BindSwapGroupToBarrier(barrier, pSwapGroup))
547                 return BadAlloc;
548         }
549         else {
550             if (!UnbindSwapGroupFromBarrier(pSwapGroup->barrier, pSwapGroup))
551                 return BadDrawable;
552         }
553 
554         /* Set the barrier for each member of this swap group */
555         for (pCur = pSwapGroup; pCur; pCur = pCur->pNext)
556             pCur->barrier = barrier;
557     }
558 
559     return Success;
560 }
561