windows-nt/Source/XPSP1/NT/multimedia/opengl/client/swapmult.c
2020-09-26 16:20:57 +08:00

480 lines
14 KiB
C

/******************************Module*Header*******************************\
* Module Name: swapmult.c
*
* wglSwapMultiple implementation
*
* Created: 02-10-1997
* Author: Drew Bliss [drewb]
*
* Copyright (c) 1993-1997 Microsoft Corporation
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include <gencx.h>
#include <mcdcx.h>
/******************************Public*Routine******************************\
*
* BufferSwapperType
*
* Determines what basic type of swapper is responsible for the given
* swap info.
*
* History:
* Mon Oct 14 18:46:28 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
#define BSWP_ICD 0
#define BSWP_MCD 1
#define BSWP_GENERIC 2
int BufferSwapperType(GENMCDSWAP *pgms)
{
// The buffer can be for an ICD, an MCD or generic
// 1. ICD buffers have an ICD pixel format
// 2. MCD buffers have MCD state
if (pgms->pwnd->ipfd <= pgms->pwnd->ipfdDevMax)
{
return BSWP_ICD;
}
else
{
if (pgms->pwnd->buffers != NULL)
{
if (pgms->pwnd->buffers->pMcdSurf != NULL)
{
return BSWP_MCD;
}
}
}
return BSWP_GENERIC;
}
/******************************Public*Routine******************************\
*
* SameSwapper
*
* Checks whether the two swapinfos are swapped by the same swapping
* agency.
*
* History:
* Mon Oct 14 18:49:26 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL SameSwapper(int iSwapperTypeA, GENMCDSWAP *pgmsA, GENMCDSWAP *pgmsB)
{
switch(iSwapperTypeA)
{
case BSWP_ICD:
// Must be the same ICD
if (BufferSwapperType(pgmsB) != BSWP_ICD ||
pgmsA->pwnd->pvDriver != pgmsB->pwnd->pvDriver)
{
return FALSE;
}
return TRUE;
case BSWP_MCD:
case BSWP_GENERIC:
// No way to refine the comparison any more
return BufferSwapperType(pgmsB) == iSwapperTypeA;
default:
ASSERTOPENGL(FALSE, "SameSwapper UNREACHED\n");
return FALSE;
}
}
/******************************Public*Routine******************************\
*
* wglSwapMultipleBuffers
*
* Swaps as many of the given buffers as possible.
* Returns a bitmask of the buffers that were swapped.
*
* History:
* Mon Oct 14 17:19:09 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
// #define VERBOSE_MULTI
DWORD WINAPI wglSwapMultipleBuffers(UINT cBuffers, CONST WGLSWAP *pwswapAll)
{
GENMCDSWAP agmsAll[WGL_SWAPMULTIPLE_MAX];
GENMCDSWAP *pgmsFirst;
GENMCDSWAP *pgmsEnd;
GENMCDSWAP *pgms;
GENMCDSWAP *apgmsGroup[WGL_SWAPMULTIPLE_MAX];
GENMCDSWAP **ppgmsGroup;
WGLSWAP *pwswap;
DWORD dwMask;
UINT uiCur;
UINT uiIdx;
GLWINDOWID gwid;
GLGENwindow *pwnd;
DWORD dwBit;
DWORD dwCallMask;
DWORD adwCallIndex[WGL_SWAPMULTIPLE_MAX];
DWORD *pdwCallIndex;
DWORD cGroup;
DWORD cDone;
int iSwapperType;
BOOL bCall;
ASSERTOPENGL(WGL_SWAPMULTIPLE_MAX <= 16,
"WGL_SWAPMULTIPLE_MAX too large\n");
ASSERTOPENGL(WGL_SWAPMULTIPLE_MAX == OPENGLCMD_MAXMULTI &&
WGL_SWAPMULTIPLE_MAX == MCDESC_MAX_EXTRA_WNDOBJ,
"WGL_SWAPMULTIPLE_MAX mismatch\n");
if (cBuffers > WGL_SWAPMULTIPLE_MAX)
{
SetLastError(ERROR_INVALID_FUNCTION);
return 0;
}
dwMask = 0;
// Validate all input buffers and do one-time information gathering for
// them.
pgms = agmsAll;
pwswap = (WGLSWAP *)pwswapAll;
for (uiCur = 0; uiCur < cBuffers; uiCur++, pwswap++)
{
// Validate DC
if (IsDirectDrawDevice(pwswap->hdc))
{
continue;
}
switch(GetObjectType(pwswap->hdc))
{
case OBJ_DC:
break;
case OBJ_MEMDC:
// Nothing to do for memdc
dwMask |= 1 << uiCur;
// Fall through
default:
continue;
}
// Look up pwnd
WindowIdFromHdc(pwswap->hdc, &gwid);
pwnd = pwndGetFromID(&gwid);
if (pwnd == NULL)
{
continue;
}
if (pwnd->ipfd == 0)
{
pwndRelease(pwnd);
continue;
}
// We have a valid candidate for swapping. Remember it.
pgms->pwswap = pwswap;
pgms->pwnd = pwnd;
pgms++;
}
#ifdef VERBOSE_MULTI
DbgPrint("%d cand\n", pgms-agmsAll);
#endif
// Walk list of candidates and gather by swapper
pgmsEnd = pgms;
pgmsFirst = agmsAll;
while (pgmsFirst < pgmsEnd)
{
// Skip over any candidates that have already been swapped
if (pgmsFirst->pwswap == NULL)
{
pgmsFirst++;
continue;
}
iSwapperType = BufferSwapperType(pgmsFirst);
#ifdef VERBOSE_MULTI
DbgPrint(" Gathering for %d, type %d\n", pgmsFirst-agmsAll,
iSwapperType);
#endif
ppgmsGroup = apgmsGroup;
*ppgmsGroup++ = pgmsFirst;
pgmsFirst++;
pgms = pgmsFirst;
while (pgms < pgmsEnd)
{
if (pgms->pwswap != NULL)
{
if (SameSwapper(iSwapperType, apgmsGroup[0], pgms))
{
#ifdef VERBOSE_MULTI
DbgPrint(" Match with %d\n", pgms-agmsAll);
#endif
*ppgmsGroup++ = pgms;
}
}
pgms++;
}
// Dispatch group to swapper for swapping. This may require
// multiple attempts because the same swapper may be responsible
// for multiple devices and only one device can be handled at
// a time.
cGroup = (DWORD)((ULONG_PTR)(ppgmsGroup-apgmsGroup));
#ifdef VERBOSE_MULTI
DbgPrint(" Group of %d\n", cGroup);
#endif
cDone = 0;
while (cDone < cGroup)
{
WGLSWAP awswapIcdCall[WGL_SWAPMULTIPLE_MAX];
PGLDRIVER pgldrv;
GENMCDSWAP agmsMcdCall[WGL_SWAPMULTIPLE_MAX];
GENMCDSWAP *pgmsCall;
// Collect any remaining swaps into calling format
pdwCallIndex = adwCallIndex;
pgms = NULL;
// After each case, uiCur must be set to the number of
// swaps attempted and dwMask must be set to the
// attempted/succeeded mask.
switch(iSwapperType)
{
case BSWP_ICD:
pwswap = awswapIcdCall;
for (uiCur = 0; uiCur < cGroup; uiCur++)
{
if (apgmsGroup[uiCur] != NULL)
{
pgms = apgmsGroup[uiCur];
*pwswap++ = *pgms->pwswap;
*pdwCallIndex++ = uiCur;
}
}
uiCur = (UINT)((ULONG_PTR)(pwswap-awswapIcdCall));
// Quit if nothing remaining
if (uiCur == 0)
{
dwCallMask = 0;
}
else
{
pgldrv = (PGLDRIVER)pgms->pwnd->pvDriver;
ASSERTOPENGL(pgldrv != NULL,
"ICD not loaded\n");
// Ask for swap
// If the ICD supports SwapMultiple, pass the call on
if (pgldrv->pfnDrvSwapMultipleBuffers != NULL)
{
dwCallMask = pgldrv->
pfnDrvSwapMultipleBuffers(uiCur, awswapIcdCall);
}
else if (pgldrv->pfnDrvSwapLayerBuffers != NULL)
{
// The ICD doesn't support multiple swap but
// it does support layer swaps so iterate
// through all the separate swaps.
dwCallMask = 0;
dwBit = 1 << (uiCur-1);
while (--pwswap >= awswapIcdCall)
{
// Every swap is attempted
dwCallMask |= dwBit << (32-WGL_SWAPMULTIPLE_MAX);
if (pgldrv->
pfnDrvSwapLayerBuffers(pwswap->hdc,
pwswap->uiFlags))
{
dwCallMask |= dwBit;
}
dwBit >>= 1;
}
}
else
{
// The ICD only supports SwapBuffers so
// iterate and swap all main plane requests.
// Any overlay plane swaps are ignored and
// reported as successful.
dwCallMask = 0;
dwBit = 1 << (uiCur-1);
while (--pwswap >= awswapIcdCall)
{
// Every swap is attempted
dwCallMask |= dwBit << (32-WGL_SWAPMULTIPLE_MAX);
if (pwswap->uiFlags & WGL_SWAP_MAIN_PLANE)
{
bCall = __DrvSwapBuffers(pwswap->hdc, FALSE);
}
else
{
bCall = TRUE;
}
if (bCall)
{
dwCallMask |= dwBit;
}
dwBit >>= 1;
}
}
}
break;
case BSWP_MCD:
pgmsCall = agmsMcdCall;
for (uiCur = 0; uiCur < cGroup; uiCur++)
{
if (apgmsGroup[uiCur] != NULL)
{
pgms = apgmsGroup[uiCur];
*pgmsCall++ = *pgms;
*pdwCallIndex++ = uiCur;
}
}
uiCur = (UINT)((ULONG_PTR)(pgmsCall-agmsMcdCall));
// Quit if nothing remaining
if (uiCur == 0)
{
dwCallMask = 0;
}
else
{
// Ask for swap
dwCallMask = GenMcdSwapMultiple(uiCur, agmsMcdCall);
}
break;
case BSWP_GENERIC:
// No accleration exists so just iterate and swap
dwCallMask = 0;
dwBit = 1;
for (uiCur = 0; uiCur < cGroup; uiCur++)
{
pgms = apgmsGroup[uiCur];
*pdwCallIndex++ = uiCur;
// Every swap is attempted
dwCallMask |= dwBit << (32-WGL_SWAPMULTIPLE_MAX);
// Since this is a generic swap we only swap the
// main plane. Overlay planes are ignored and
// reported as successful.
if (pgms->pwswap->uiFlags & WGL_SWAP_MAIN_PLANE)
{
ENTER_WINCRIT(pgms->pwnd);
bCall = glsrvSwapBuffers(pgms->pwswap->hdc,
pgms->pwnd);
LEAVE_WINCRIT(pgms->pwnd);
}
else
{
bCall = TRUE;
}
if (bCall)
{
dwCallMask |= dwBit;
}
dwBit <<= 1;
}
break;
}
#ifdef VERBOSE_MULTI
DbgPrint(" Attempted %d, mask %X\n", uiCur, dwCallMask);
#endif
// Quit if nothing was swapped.
if (dwCallMask == 0)
{
break;
}
// Determine which buffers were really swapped and
// clear any buffers for which a swap was attempted.
dwBit = 1 << (uiCur-1);
while (uiCur-- > 0)
{
uiIdx = adwCallIndex[uiCur];
pgms = apgmsGroup[uiIdx];
if (dwCallMask & dwBit)
{
dwMask |= 1 << (pgms->pwswap-pwswapAll);
}
if ((dwCallMask >> (32-WGL_SWAPMULTIPLE_MAX)) & dwBit)
{
// Take out of overall list
pgms->pwswap = NULL;
// Take out of group list
apgmsGroup[uiIdx] = NULL;
cDone++;
}
dwBit >>= 1;
}
#ifdef VERBOSE_MULTI
DbgPrint(" Done with %d, mask %X\n", cDone, dwMask);
#endif
}
}
// Release all the pwnds
pgms = agmsAll;
while (pgms < pgmsEnd)
{
pwndRelease(pgms->pwnd);
pgms++;
}
#ifdef VERBOSE_MULTI
DbgPrint("Final mask %X\n", dwMask);
#endif
return dwMask;
}