#ifdef HAVE_DMX_CONFIG_H
#include <dmx-config.h>
#endif
#include "dmx.h"
#include "dmxwindow.h"
#include "glxserver.h"
#include "glxswap.h"
extern int __glXDoSwapBuffers(__GLXclientState *cl, XID drawId,
GLXContextTag tag);
typedef struct _SwapGroup *SwapGroupPtr;
static Bool SwapBarrierIsReadyToSwap(GLuint barrier);
static void SwapSwapBarrier(GLuint barrier);
static void UpdateSwapBarrierList(GLuint barrier,
SwapGroupPtr pOldSwap,
SwapGroupPtr pNewSwap);
typedef struct _SwapGroup {
WindowPtr pWin;
SwapGroupPtr pNext;
Bool swapping;
Bool sleeping;
GLuint barrier;
XID drawable;
GLXContextTag tag;
__GLXclientState *clState;
} SwapGroupRec;
static void SwapSwapGroup(SwapGroupPtr pSwap)
{
SwapGroupPtr pCur;
for (pCur = pSwap; pCur; pCur = pCur->pNext) {
if (pCur->swapping) {
__glXDoSwapBuffers(pCur->clState, pCur->drawable, pCur->tag);
pCur->swapping = FALSE;
}
if (pCur->sleeping) {
ClientWakeup(pCur->clState->client);
pCur->sleeping = FALSE;
}
}
}
static Bool SwapGroupIsReadyToSwap(SwapGroupPtr pSwap)
{
Bool isReady = TRUE;
for (; pSwap; pSwap = pSwap->pNext) {
isReady &= (pSwap->swapping || !pSwap->pWin->mapped);
}
return isReady;
}
static Bool SGSwapCleanup(ClientPtr client, pointer closure)
{
return TRUE;
}
int SGSwapBuffers(__GLXclientState *cl, XID drawId, GLXContextTag tag,
DrawablePtr pDraw)
{
WindowPtr pWin = (WindowPtr)pDraw;
dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
SwapGroupPtr pSwap = pWinPriv->swapGroup;
SwapGroupPtr pCur;
for (pCur = pSwap; pCur && pCur->pWin != pWin; pCur = pCur->pNext);
if (!pCur)
return BadDrawable;
pCur->clState = cl;
pCur->drawable = drawId;
pCur->tag = tag;
pCur->swapping = TRUE;
if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) {
SwapSwapBarrier(pSwap->barrier);
} else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) {
SwapSwapGroup(pSwap);
} else {
ClientSleep(cl->client, SGSwapCleanup, (pointer)pWin);
pCur->sleeping = TRUE;
}
return Success;
}
static void SGWindowUnmapped(WindowPtr pWin)
{
dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
SwapGroupPtr pSwap = pWinPriv->swapGroup;
if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) {
SwapSwapBarrier(pSwap->barrier);
} else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) {
SwapSwapGroup(pSwap);
}
}
static void SGWindowDestroyed(WindowPtr pWin)
{
JoinSwapGroupSGIX((DrawablePtr)pWin, NULL);
}
static SwapGroupPtr CreateSwapEntry(WindowPtr pWin)
{
SwapGroupPtr pEntry;
pEntry = xalloc(sizeof(*pEntry));
if (!pEntry) return NULL;
pEntry->pWin = pWin;
pEntry->pNext = NULL;
pEntry->swapping = FALSE;
pEntry->sleeping = FALSE;
pEntry->barrier = 0;
return pEntry;
}
static void FreeSwapEntry(SwapGroupPtr pEntry)
{
if (pEntry->swapping)
__glXDoSwapBuffers(pEntry->clState, pEntry->drawable, pEntry->tag);
if (pEntry->sleeping)
ClientWakeup(pEntry->clState->client);
xfree(pEntry);
}
int JoinSwapGroupSGIX(DrawablePtr pDraw, DrawablePtr pMember)
{
if (pDraw->type == DRAWABLE_WINDOW) {
WindowPtr pWin = (WindowPtr)pDraw;
dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
SwapGroupPtr pOldSwap = NULL;
SwapGroupPtr pEntry;
for (pEntry = pWinPriv->swapGroup; pEntry; pEntry = pEntry->pNext)
if (pEntry->pWin == (WindowPtr)pMember)
return Success;
if (pWinPriv->swapGroup) {
SwapGroupPtr pSwapGroup = pWinPriv->swapGroup;
SwapGroupPtr pPrev;
for (pOldSwap = pWinPriv->swapGroup, pPrev = NULL;
pOldSwap && pOldSwap->pWin != pWin;
pPrev = pOldSwap, pOldSwap = pOldSwap->pNext);
if (!pOldSwap)
return BadDrawable;
if (pPrev) {
pPrev->pNext = pOldSwap->pNext;
} else {
for (pEntry = pOldSwap->pNext; pEntry; pEntry = pEntry->pNext)
DMX_GET_WINDOW_PRIV(pEntry->pWin)->swapGroup
= pOldSwap->pNext;
if (pOldSwap->barrier)
UpdateSwapBarrierList(pOldSwap->barrier,
pOldSwap, pOldSwap->pNext);
pSwapGroup = pOldSwap->pNext;
}
if (pSwapGroup && SwapGroupIsReadyToSwap(pSwapGroup)) {
SwapSwapGroup(pSwapGroup);
}
pOldSwap->pNext = NULL;
pOldSwap->barrier = 0;
pWinPriv->swapGroup = NULL;
pWinPriv->windowDestroyed = NULL;
pWinPriv->windowUnmapped = NULL;
}
if (!pMember || pMember->type != DRAWABLE_WINDOW) {
if (pOldSwap) FreeSwapEntry(pOldSwap);
} else if (pDraw == pMember && pOldSwap) {
pWinPriv->swapGroup = pOldSwap;
pWinPriv->windowDestroyed = SGWindowDestroyed;
pWinPriv->windowUnmapped = SGWindowUnmapped;
if (SwapGroupIsReadyToSwap(pOldSwap))
SwapSwapGroup(pOldSwap);
} else if (pMember->type == DRAWABLE_WINDOW) {
WindowPtr pMemberWin = (WindowPtr)pMember;
dmxWinPrivPtr pMemberPriv = DMX_GET_WINDOW_PRIV(pMemberWin);
SwapGroupPtr pMemberSwapGroup = pMemberPriv->swapGroup;
if (!pMemberSwapGroup) {
pMemberSwapGroup = CreateSwapEntry(pMemberWin);
if (!pMemberSwapGroup) {
if (pOldSwap) FreeSwapEntry(pOldSwap);
return BadAlloc;
}
pMemberPriv->swapGroup = pMemberSwapGroup;
pMemberPriv->windowDestroyed = SGWindowDestroyed;
pMemberPriv->windowUnmapped = SGWindowUnmapped;
}
if (pDraw != pMember) {
if (!pOldSwap) {
pOldSwap = CreateSwapEntry(pWin);
if (!pOldSwap) {
if (pMemberSwapGroup->pNext == NULL) {
FreeSwapEntry(pMemberSwapGroup);
pMemberPriv->swapGroup = NULL;
}
return BadAlloc;
}
}
for (pEntry = pMemberSwapGroup;
pEntry->pNext;
pEntry = pEntry->pNext);
pEntry->pNext = pOldSwap;
pOldSwap->barrier = pEntry->barrier;
pWinPriv->swapGroup = pMemberSwapGroup;
pWinPriv->windowDestroyed = SGWindowDestroyed;
pWinPriv->windowUnmapped = SGWindowUnmapped;
}
}
}
return Success;
}
#define GLX_MAX_SWAP_BARRIERS 10
typedef struct _SwapBarrier *SwapBarrierPtr;
typedef struct _SwapBarrier {
SwapGroupPtr pSwap;
SwapBarrierPtr pNext;
} SwapBarrierRec;
static SwapBarrierPtr SwapBarrierList[GLX_MAX_SWAP_BARRIERS+1];
void SwapBarrierInit(void)
{
int i;
for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++)
SwapBarrierList[i] = NULL;
}
void SwapBarrierReset(void)
{
int i;
for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) {
SwapBarrierPtr pBarrier, pNextBarrier;;
for (pBarrier = SwapBarrierList[i];
pBarrier;
pBarrier = pNextBarrier) {
pNextBarrier = pBarrier->pNext;
xfree(pBarrier);
}
SwapBarrierList[i] = NULL;
}
}
int QueryMaxSwapBarriersSGIX(int screen)
{
return GLX_MAX_SWAP_BARRIERS;
}
static Bool BindSwapGroupToBarrier(GLuint barrier, SwapGroupPtr pSwapGroup)
{
SwapBarrierPtr pBarrier;
pBarrier = xalloc(sizeof(*pBarrier));
if (!pBarrier) return FALSE;
pBarrier->pSwap = pSwapGroup;
pBarrier->pNext = SwapBarrierList[barrier];
SwapBarrierList[barrier] = pBarrier;
return TRUE;
}
static Bool UnbindSwapGroupFromBarrier(GLuint barrier, SwapGroupPtr pSwapGroup)
{
SwapBarrierPtr pBarrier, pPrevBarrier;
for (pBarrier = SwapBarrierList[barrier], pPrevBarrier = NULL;
pBarrier && pBarrier->pSwap != pSwapGroup;
pPrevBarrier = pBarrier, pBarrier = pBarrier->pNext);
if (!pBarrier) return FALSE;
if (pPrevBarrier) pPrevBarrier->pNext = pBarrier->pNext;
else SwapBarrierList[barrier] = pBarrier->pNext;
xfree(pBarrier);
return TRUE;
}
static void UpdateSwapBarrierList(GLuint barrier,
SwapGroupPtr pOldSwap,
SwapGroupPtr pNewSwap)
{
SwapBarrierPtr pBarrier;
if (!pNewSwap) {
UnbindSwapGroupFromBarrier(barrier, pOldSwap);
return;
}
for (pBarrier = SwapBarrierList[barrier];
pBarrier;
pBarrier = pBarrier->pNext) {
if (pBarrier->pSwap == pOldSwap) {
pBarrier->pSwap = pNewSwap;
return;
}
}
}
static Bool SwapBarrierIsReadyToSwap(GLuint barrier)
{
SwapBarrierPtr pBarrier;
Bool isReady = TRUE;
for (pBarrier = SwapBarrierList[barrier];
pBarrier;
pBarrier = pBarrier->pNext)
isReady &= SwapGroupIsReadyToSwap(pBarrier->pSwap);
return isReady;
}
static void SwapSwapBarrier(GLuint barrier)
{
SwapBarrierPtr pBarrier;
for (pBarrier = SwapBarrierList[barrier];
pBarrier;
pBarrier = pBarrier->pNext)
SwapSwapGroup(pBarrier->pSwap);
}
int BindSwapBarrierSGIX(DrawablePtr pDraw, int barrier)
{
if (barrier < 0 || barrier > GLX_MAX_SWAP_BARRIERS)
return BadValue;
if (pDraw->type == DRAWABLE_WINDOW) {
WindowPtr pWin = (WindowPtr)pDraw;
dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
SwapGroupPtr pSwapGroup = pWinPriv->swapGroup;
SwapGroupPtr pCur;
if (!pSwapGroup) return BadDrawable;
if (barrier && pSwapGroup->barrier) return BadValue;
if (barrier) {
if (!BindSwapGroupToBarrier(barrier, pSwapGroup))
return BadAlloc;
} else {
if (!UnbindSwapGroupFromBarrier(pSwapGroup->barrier, pSwapGroup))
return BadDrawable;
}
for (pCur = pSwapGroup; pCur; pCur = pCur->pNext)
pCur->barrier = barrier;
}
return Success;
}