| 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 | |
| 43 | extern int __glXDoSwapBuffers(__GLXclientState * cl, XID drawId, |
| 44 | GLXContextTag tag); |
| 45 | |
| 46 | typedef struct _SwapGroup *SwapGroupPtr; |
| 47 | |
| 48 | static Bool SwapBarrierIsReadyToSwap(GLuint barrier); |
| 49 | static void SwapSwapBarrier(GLuint barrier); |
| 50 | static void UpdateSwapBarrierList(GLuint barrier, |
| 51 | SwapGroupPtr pOldSwap, SwapGroupPtr pNewSwap); |
| 52 | |
| 53 | /************************************************************************ |
| 54 | * |
| 55 | * Swap Groups |
| 56 | * |
| 57 | ************************************************************************/ |
| 58 | |
| 59 | typedef 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 | |
| 72 | static void |
| 73 | SwapSwapGroup(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 | |
| 96 | static Bool |
| 97 | SwapGroupIsReadyToSwap(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 | |
| 112 | static Bool |
| 113 | SGSwapCleanup(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 | |
| 123 | int |
| 124 | SGSwapBuffers(__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 | |
| 164 | static void |
| 165 | SGWindowUnmapped(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 | |
| 181 | static void |
| 182 | SGWindowDestroyed(WindowPtr pWin) |
| 183 | { |
| 184 | JoinSwapGroupSGIX((DrawablePtr) pWin, NULL); |
| 185 | } |
| 186 | |
| 187 | static SwapGroupPtr |
| 188 | CreateSwapEntry(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 | |
| 212 | static void |
| 213 | FreeSwapEntry(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 | |
| 238 | int |
| 239 | JoinSwapGroupSGIX(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 | |
| 397 | typedef struct _SwapBarrier *SwapBarrierPtr; |
| 398 | typedef struct _SwapBarrier { |
| 399 | SwapGroupPtr pSwap; |
| 400 | SwapBarrierPtr pNext; |
| 401 | } SwapBarrierRec; |
| 402 | |
| 403 | static SwapBarrierPtr SwapBarrierList[GLX_MAX_SWAP_BARRIERS + 1]; |
| 404 | |
| 405 | void |
| 406 | SwapBarrierInit(void) |
| 407 | { |
| 408 | int i; |
| 409 | |
| 410 | for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) |
| 411 | SwapBarrierList[i] = NULL; |
| 412 | } |
| 413 | |
| 414 | void |
| 415 | SwapBarrierReset(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 | |
| 430 | int |
| 431 | QueryMaxSwapBarriersSGIX(int screen) |
| 432 | { |
| 433 | return GLX_MAX_SWAP_BARRIERS; |
| 434 | } |
| 435 | |
| 436 | static Bool |
| 437 | BindSwapGroupToBarrier(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 | |
| 453 | static Bool |
| 454 | UnbindSwapGroupFromBarrier(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 | |
| 477 | static void |
| 478 | UpdateSwapBarrierList(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 | |
| 501 | static Bool |
| 502 | SwapBarrierIsReadyToSwap(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 | |
| 516 | static void |
| 517 | SwapSwapBarrier(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 | |
| 527 | int |
| 528 | BindSwapBarrierSGIX(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 | } |