Windows2003-3790/windows/core/dxkernel/dxapi/dxapi.cxx

3889 lines
132 KiB
C++
Raw Permalink Normal View History

2001-01-01 00:00:00 +01:00
/******************************Module*Header*******************************\
* Module Name: dxapi.cxx
*
* Contains the public kernel-mode APIs for DirectX.
*
* All of the stuff that has to happen at raised IRQL happens here, because
* win32k is entirely pageable.
*
* Created: 11-Apr-1997
* Author: J. Andrew Goossen [andrewgo]
*
* Copyright (c) 1997 Microsoft Corporation
*
\**************************************************************************/
#include "precomp.hxx"
#if DBG
#define RIPDX(x) { KdPrint((x)); DbgBreakPoint();}
#define ASSERTDX(x, y) if (!(x)) RIPDX(y)
#else
#define RIPDX(x)
#define ASSERTDX(x, y)
#endif
extern "C" {
VOID
APIENTRY
DxIrqCallBack(
DX_IRQDATA* pIrqData
);
NTSTATUS
DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath
);
VOID
APIENTRY
DxGetVersionNumber(
DWORD dwNotUsed,
DDGETVERSIONNUMBER* pGetVersionNumber
);
BOOL
bDxModifyPassiveEventList(
EDD_DXDIRECTDRAW* peDxDirectDraw,
BOOL bAdd,
DWORD dwEvent,
LPDD_NOTIFYCALLBACK pfnCallBack,
PVOID pContext
);
DWORD
dwDxRegisterEvent(
DDREGISTERCALLBACK* pRegisterEvent,
BOOL bRegister
);
VOID
APIENTRY
DxRegisterEvent(
DDREGISTERCALLBACK* pRegisterEvent,
DWORD* pdwRet
);
VOID
APIENTRY
DxUnregisterEvent(
DDREGISTERCALLBACK* pRegisterEvent,
DWORD* pdwRet
);
VOID
APIENTRY
DxOpenDirectDraw(
DDOPENDIRECTDRAWIN* pOpenDirectDrawIn,
DDOPENDIRECTDRAWOUT* pOpenDirectDrawOut
);
VOID
APIENTRY
DxApiInitialize(
PFNDXAPIOPENDIRECTDRAW pfnOpenDirectDraw,
PFNDXAPIOPENVIDEOPORT pfnOpenVideoPort,
PFNDXAPIOPENSURFACE pfnOpenSurface,
PFNDXAPICLOSEHANDLE pfnCloseHandle,
PFNDXAPIGETKERNELCAPS pfnGetKernelCaps,
PFNDXAPIOPENCAPTUREDEVICE pfnOpenCaptureDevice,
PFNDXAPILOCKDEVICE pfnLockDevice,
PFNDXAPIUNLOCKDEVICE pfnUnlockDevice
);
DWORD
APIENTRY
DxApi(
DWORD iFunction,
VOID* pInBuffer,
DWORD cInBuffer,
VOID* pOutBuffer,
DWORD cOutBuffer
);
VOID
APIENTRY
DxAutoflipDpc(
DWORD dwEvent,
PVOID pContext,
DWORD dwParam1,
DWORD dwParam2
);
VOID
APIENTRY
DxAutoflipUpdate(
EDD_DXVIDEOPORT* peDxVideoPort,
EDD_DXSURFACE** apeDxSurfaceVideo,
ULONG cSurfacesVideo,
EDD_DXSURFACE** apeDxSurfaceVbi,
ULONG cSurfacesVbi
);
VOID
APIENTRY
DxLoseObject(
VOID* pvObject,
LOTYPE loType
);
VOID
APIENTRY
DxEnableIRQ(
EDD_DXVIDEOPORT* peDxVideoPort,
BOOL bEnable
);
VOID
APIENTRY
DxUpdateCapture(
EDD_DXVIDEOPORT* peDxVideoPort,
EDD_DXCAPTURE* peDxCapture,
BOOL bRemove
);
DWORD
APIENTRY
DxApiGetVersion(
VOID
);
}; // end "extern "C"
// Marke whatever we can as pageable:
#if defined(ALLOC_PRAGMA)
#pragma alloc_text(PAGE,DriverEntry)
#pragma alloc_text(PAGE,DxGetVersionNumber)
#pragma alloc_text(PAGE,bDxModifyPassiveEventList)
#pragma alloc_text(PAGE,dwDxRegisterEvent)
#pragma alloc_text(PAGE,DxRegisterEvent)
#pragma alloc_text(PAGE,DxUnregisterEvent)
#pragma alloc_text(PAGE,DxOpenDirectDraw)
#pragma alloc_text(PAGE,DxApiInitialize)
#pragma alloc_text(PAGE,DxApiGetVersion)
#endif
PFNDXAPIOPENDIRECTDRAW gpfnOpenDirectDraw;
PFNDXAPILOCKDEVICE gpfnLockDevice;
PFNDXAPIUNLOCKDEVICE gpfnUnlockDevice;
/***************************************************************************\
* NTSTATUS DriverEntry
*
* This routine is never actually called, but we need it to link.
*
\***************************************************************************/
extern "C"
NTSTATUS
DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath
)
{
return(STATUS_SUCCESS);
}
/******************************Public*Routine******************************\
* DWORD DxGetVersionNumber
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxGetVersionNumber(
DWORD dwNotUsed,
DDGETVERSIONNUMBER* pGetVersionNumber
)
{
ASSERTDX(KeGetCurrentIrql() == PASSIVE_LEVEL,
"DxGetVersionNumber: Call only at passive level (it's not pageable)");
pGetVersionNumber->dwMajorVersion = DXAPI_MAJORVERSION;
pGetVersionNumber->dwMinorVersion = DXAPI_MINORVERSION;
pGetVersionNumber->ddRVal = DD_OK;
}
/******************************Public*Routine******************************\
* VOID DxGetFieldNumber
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxGetFieldNumber(
DDGETFIELDNUMIN* pGetFieldNumIn,
DDGETFIELDNUMOUT* pGetFieldNumOut
)
{
DXOBJ* pDxObjDirectDraw;
DXOBJ* pDxObjVideoPort;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXVIDEOPORT* peDxVideoPort;
pGetFieldNumOut->ddRVal = DDERR_INVALIDPARAMS;
if (pGetFieldNumIn == NULL)
{
return;
}
pDxObjDirectDraw = (DXOBJ*) pGetFieldNumIn->hDirectDraw;
if (pDxObjDirectDraw != NULL)
{
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
pDxObjVideoPort = (DXOBJ*) pGetFieldNumIn->hVideoPort;
if (pDxObjVideoPort != NULL)
{
peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW,
"Invalid DirectDraw object");
ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT,
"Invalid VideoPort object");
ASSERTDX(peDxDirectDraw == peDxVideoPort->peDxDirectDraw,
"VideoPort and DirectDraw objects don't match");
if (peDxVideoPort->peDxDirectDraw->dwIRQCaps & DDIRQ_VPORT0_VSYNC )
{
pGetFieldNumOut->dwFieldNum = peDxVideoPort->dwCurrentField;
pGetFieldNumOut->ddRVal = DD_OK;
}
else
{
KdPrint(("DxGetFieldNumber: Device doesn't support an interrupt\n"));
pGetFieldNumOut->ddRVal = DDERR_UNSUPPORTED;
}
}
}
}
/******************************Public*Routine******************************\
* VOID DxSetFieldNumber
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxSetFieldNumber(
DDSETFIELDNUM* pSetFieldNum,
DWORD* pdwRet
)
{
DXOBJ* pDxObjDirectDraw;
DXOBJ* pDxObjVideoPort;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXVIDEOPORT* peDxVideoPort;
*pdwRet = DDERR_INVALIDPARAMS;
if (pSetFieldNum == NULL)
{
return;
}
pDxObjDirectDraw = (DXOBJ*) pSetFieldNum->hDirectDraw;
if (pDxObjDirectDraw != NULL)
{
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
pDxObjVideoPort = (DXOBJ*) pSetFieldNum->hVideoPort;
if (pDxObjVideoPort != NULL)
{
peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW,
"Invalid DirectDraw object");
ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT,
"Invalid VideoPort object");
ASSERTDX(peDxDirectDraw == peDxVideoPort->peDxDirectDraw,
"VideoPort and DirectDraw objects don't match");
if (peDxVideoPort->peDxDirectDraw->dwIRQCaps & DDIRQ_VPORT0_VSYNC )
{
peDxVideoPort->dwCurrentField = pSetFieldNum->dwFieldNum;
*pdwRet = DD_OK;
}
else
{
KdPrint(("DxSetFieldNumber: Device doesn't support an interrupt\n"));
*pdwRet = DDERR_UNSUPPORTED;
}
}
}
}
/******************************Public*Routine******************************\
* VOID DxSetSkipPattern
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxSetSkipPattern(
DDSETSKIPFIELD* pSetSkipPattern,
DWORD* pdwRet
)
{
DXOBJ* pDxObjDirectDraw;
DXOBJ* pDxObjVideoPort;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXVIDEOPORT* peDxVideoPort;
KIRQL OldIrql;
DWORD dwStartField;
*pdwRet = DDERR_INVALIDPARAMS;
if (pSetSkipPattern == NULL)
{
return;
}
pDxObjDirectDraw = (DXOBJ*) pSetSkipPattern->hDirectDraw;
if (pDxObjDirectDraw != NULL)
{
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
pDxObjVideoPort = (DXOBJ*) pSetSkipPattern->hVideoPort;
if (pDxObjVideoPort != NULL)
{
peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW,
"Invalid DirectDraw object");
ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT,
"Invalid VideoPort object");
ASSERTDX(peDxDirectDraw == peDxVideoPort->peDxDirectDraw,
"VideoPort and DirectDraw objects don't match");
// Acquire the spinlock while we muck around
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
// We assume that we are called during the VSYNC callback notification
// so all that we do is store the value and do the actual skipping
// during the AutoflipDpc call.
dwStartField = pSetSkipPattern->dwStartField;
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_SKIP_SET )
{
if( peDxVideoPort->dwFieldToSkip > dwStartField )
{
peDxVideoPort->dwNextFieldToSkip = peDxVideoPort->dwFieldToSkip;
peDxVideoPort->dwFieldToSkip = dwStartField;
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_NEXT_SKIP_SET;
}
else if ( dwStartField != peDxVideoPort->dwFieldToSkip )
{
peDxVideoPort->dwFieldToSkip = dwStartField;
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_NEXT_SKIP_SET;
}
}
else
{
peDxVideoPort->dwFieldToSkip = dwStartField;
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_SKIP_SET;
}
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
*pdwRet = DX_OK;
}
}
}
/******************************Public*Routine******************************\
* VOID EffectStateChange
*
* 09-Jan-1998 -by- Scott MacDonald [smac]
* Wrote it.
\**************************************************************************/
VOID EffectStateChange( EDD_DXVIDEOPORT* peDxVideoPort,
EDD_DXSURFACE* peDxSurface, DWORD dwNewState )
{
EDD_DXDIRECTDRAW* peDxDirectDraw;
DDSETSTATEININFO ddStateInInfo;
DDSETSTATEOUTINFO ddStateOutInfo;
DWORD dwOldFlags;
DWORD dwOldVPFlags;
DWORD ddRVal;
DWORD i;
DWORD dwRet;
dwOldVPFlags = 0;
if( peDxVideoPort != NULL )
{
peDxVideoPort->dwSetStateState = 0;
peDxSurface = peDxVideoPort->apeDxSurfaceVideo[0];
dwOldVPFlags = peDxVideoPort->dwVPFlags;
if( dwNewState & DDSTATE_SKIPEVENFIELDS )
{
peDxVideoPort->dwVPFlags |= DDVP_SKIPEVENFIELDS;
}
else
{
peDxVideoPort->dwVPFlags &= ~DDVP_SKIPEVENFIELDS;
}
}
if( peDxSurface != NULL )
{
dwOldFlags = peDxSurface->dwOverlayFlags;
if( dwNewState & DDSTATE_BOB )
{
peDxSurface->dwOverlayFlags |= DDOVER_BOB;
}
else if( dwNewState & ( DDSTATE_WEAVE | DDSTATE_SKIPEVENFIELDS ) )
{
peDxSurface->dwOverlayFlags &= ~DDOVER_BOB;
}
peDxDirectDraw = peDxSurface->peDxDirectDraw;
ddStateInInfo.lpSurfaceData = peDxSurface;
ddStateInInfo.lpVideoPortData = peDxVideoPort;
ddStateOutInfo.bSoftwareAutoflip = 0;
dwRet = DDERR_UNSUPPORTED;
if (peDxDirectDraw->DxApiInterface.DxSetState != NULL)
{
dwRet = peDxDirectDraw->DxApiInterface.DxSetState(
peDxDirectDraw->HwDeviceExtension,
&ddStateInInfo,
&ddStateOutInfo);
}
if( dwRet != DD_OK )
{
peDxSurface->dwOverlayFlags = dwOldFlags;
if( peDxVideoPort != NULL )
{
peDxVideoPort->dwVPFlags = dwOldVPFlags;
}
}
peDxSurface->flFlags |= DD_DXSURFACE_FLAG_STATE_SET;
if( peDxVideoPort != NULL )
{
if( peDxSurface->dwOverlayFlags & DDOVER_BOB )
{
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_BOB;
}
else
{
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_BOB;
}
// Do they want to switch from hardware autoflipping to
// software autoflipping?
if( ( ddStateOutInfo.bSoftwareAutoflip ) &&
( peDxVideoPort->dwVPFlags & DDVP_AUTOFLIP ) &&
!( peDxVideoPort->flFlags & (DD_DXVIDEOPORT_FLAG_AUTOFLIP|DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI)))
{
if( peDxVideoPort->cAutoflipVideo > 0 )
{
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_AUTOFLIP;
}
if( peDxVideoPort->cAutoflipVbi > 0 )
{
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI;
}
if( ddStateOutInfo.dwSurfaceIndex >= peDxVideoPort->cAutoflipVideo )
{
peDxVideoPort->iCurrentVideo = 0;
}
else
{
peDxVideoPort->iCurrentVideo = ddStateOutInfo.dwSurfaceIndex;
}
if( ddStateOutInfo.dwVBISurfaceIndex >= peDxVideoPort->cAutoflipVbi )
{
peDxVideoPort->iCurrentVbi = 0;
}
else
{
peDxVideoPort->iCurrentVbi = ddStateOutInfo.dwVBISurfaceIndex;
}
}
for( i = 0; i < peDxVideoPort->iCurrentVideo; i++ )
{
peDxSurface = peDxVideoPort->apeDxSurfaceVideo[i];
peDxSurface->flFlags &= ~(DD_DXSURFACE_FLAG_STATE_BOB|DD_DXSURFACE_FLAG_STATE_WEAVE);
if( dwNewState & DDSTATE_BOB )
{
peDxSurface->dwOverlayFlags |= DDOVER_BOB;
peDxSurface->flFlags |= DD_DXSURFACE_FLAG_STATE_BOB;
}
else if( dwNewState & ( DDSTATE_WEAVE | DDSTATE_SKIPEVENFIELDS ) )
{
peDxSurface->dwOverlayFlags &= ~DDOVER_BOB;
if( dwNewState == DDSTATE_WEAVE )
{
peDxSurface->flFlags |= DD_DXSURFACE_FLAG_STATE_WEAVE;
}
}
peDxSurface->flFlags |= DD_DXSURFACE_FLAG_STATE_SET;
}
}
}
}
/******************************Public*Routine******************************\
* VOID DxGetSurfaceState
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxGetSurfaceState(
DDGETSURFACESTATEIN* pGetSurfaceStateIn,
DDGETSURFACESTATEOUT* pGetSurfaceStateOut
)
{
DXOBJ* pDxObjDirectDraw;
DXOBJ* pDxObjSurface;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXVIDEOPORT* peDxVideoPort;
EDD_DXSURFACE* peDxSurface;
pGetSurfaceStateOut->ddRVal = DDERR_INVALIDPARAMS;
if (pGetSurfaceStateIn == NULL)
{
return;
}
pDxObjDirectDraw = (DXOBJ*) pGetSurfaceStateIn->hDirectDraw;
pDxObjSurface = (DXOBJ*) pGetSurfaceStateIn->hSurface;
if ((pDxObjDirectDraw != NULL) &&
(pDxObjSurface != NULL))
{
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
peDxSurface = pDxObjSurface->peDxSurface;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW,
"Invalid DirectDraw object");
ASSERTDX(pDxObjSurface->iDxType == DXT_SURFACE,
"Invalid Surface object");
ASSERTDX(peDxDirectDraw == peDxSurface->peDxDirectDraw,
"Surface and DirectDraw objects don't match");
ASSERTDX(peDxSurface->ddsCaps & DDSCAPS_OVERLAY,
"Surface is not an overlay surface");
// Fill in the available caps
pGetSurfaceStateOut->dwStateCaps = 0;
pGetSurfaceStateOut->dwStateStatus = 0;
peDxVideoPort = peDxSurface->peDxVideoPort;
// If the DDOVER_OVERRIDEBOBWEAVE flag was set, the status is equal
// to the caps.
if( peDxSurface->dwOverlayFlags & DDOVER_OVERRIDEBOBWEAVE )
{
if( peDxSurface->dwOverlayFlags & DDOVER_BOB )
{
pGetSurfaceStateOut->dwStateStatus |= DDSTATE_BOB;
pGetSurfaceStateOut->dwStateCaps |= DDSTATE_BOB;
}
else if( ( peDxVideoPort != NULL ) &&
( peDxVideoPort->dwVPFlags & (DDVP_SKIPEVENFIELDS|DDVP_SKIPODDFIELDS) ) )
{
pGetSurfaceStateOut->dwStateStatus |= DDSTATE_SKIPEVENFIELDS;
pGetSurfaceStateOut->dwStateCaps |= DDSTATE_SKIPEVENFIELDS;
}
else if( ( peDxVideoPort != NULL ) &&
( peDxVideoPort->dwVPFlags & DDVP_INTERLEAVE ) )
{
pGetSurfaceStateOut->dwStateStatus |= DDSTATE_WEAVE;
pGetSurfaceStateOut->dwStateCaps |= DDSTATE_WEAVE;
}
else if( ( peDxVideoPort == NULL ) &&
( peDxSurface->dwOverlayFlags & DDOVER_INTERLEAVED ) )
{
pGetSurfaceStateOut->dwStateStatus |= DDSTATE_WEAVE;
pGetSurfaceStateOut->dwStateCaps |= DDSTATE_WEAVE;
}
}
else
{
// The status is different from the caps
if( ( peDxVideoPort != NULL ) &&
( peDxVideoPort->dwVPFlags & (DDVP_SKIPEVENFIELDS|DDVP_SKIPODDFIELDS) ) )
{
pGetSurfaceStateOut->dwStateStatus |= DDSTATE_SKIPEVENFIELDS;
}
else if( peDxSurface->dwOverlayFlags & DDOVER_BOB )
{
pGetSurfaceStateOut->dwStateStatus |= DDSTATE_BOB;
}
if( ( ( peDxVideoPort != NULL ) &&
( peDxVideoPort->dwVPFlags & DDVP_INTERLEAVE ) ) ||
( ( peDxVideoPort == NULL ) &&
( peDxSurface->dwOverlayFlags & DDOVER_INTERLEAVED ) ) )
{
pGetSurfaceStateOut->dwStateCaps |= DDSTATE_WEAVE;
if( peDxSurface->flFlags & DD_DXSURFACE_FLAG_CAN_BOB_INTERLEAVED )
{
pGetSurfaceStateOut->dwStateCaps |= DDSTATE_BOB;
}
if( pGetSurfaceStateOut->dwStateStatus == 0 )
{
pGetSurfaceStateOut->dwStateStatus |= DDSTATE_WEAVE;
}
}
else if( peDxSurface->flFlags & DD_DXSURFACE_FLAG_CAN_BOB_NONINTERLEAVED )
{
pGetSurfaceStateOut->dwStateCaps |= DDSTATE_BOB;
}
if( peDxVideoPort != NULL )
{
pGetSurfaceStateOut->dwStateCaps |= DDSTATE_SKIPEVENFIELDS;
}
}
// Notify the client that the state was explicity set by a
// kernel mode client.
if( peDxSurface->flFlags & DD_DXSURFACE_FLAG_STATE_SET )
{
pGetSurfaceStateOut->dwStateStatus |= DDSTATE_EXPLICITLY_SET;
}
// Tell if software autoflipping vs. hardware autofliping. This
// is mostly for DDraw's benefit.
if( ( peDxVideoPort != NULL ) && ( peDxVideoPort->bSoftwareAutoflip ) )
{
pGetSurfaceStateOut->dwStateStatus |= DDSTATE_SOFTWARE_AUTOFLIP;
}
pGetSurfaceStateOut->ddRVal = DD_OK;
}
}
/******************************Public*Routine******************************\
* VOID DxSetSurfaceState
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxSetSurfaceState(
DDSETSURFACESTATE* pSetSurfaceState,
DWORD* pdwRet
)
{
DWORD dwState;
DXOBJ* pDxObjDirectDraw;
DXOBJ* pDxObjSurface;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXVIDEOPORT* peDxVideoPort;
EDD_DXSURFACE* peDxSurface;
DDGETSURFACESTATEIN GetSurfaceStateIn;
DDGETSURFACESTATEOUT GetSurfaceStateOut;
DDSETSTATEININFO SetStateInInfo;
DDSETSTATEOUTINFO SetStateOutInfo;
DWORD iCurrentVideo;
KIRQL OldIrql;
DWORD dwRet;
DWORD dwVPFlags;
*pdwRet = dwRet = DDERR_INVALIDPARAMS;
if (pSetSurfaceState == NULL)
{
return;
}
pDxObjDirectDraw = (DXOBJ*) pSetSurfaceState->hDirectDraw;
pDxObjSurface = (DXOBJ*) pSetSurfaceState->hSurface;
if ((pDxObjDirectDraw != NULL) &&
(pDxObjSurface != NULL))
{
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
peDxSurface = pDxObjSurface->peDxSurface;
GetSurfaceStateIn.hDirectDraw = pSetSurfaceState->hDirectDraw;
GetSurfaceStateIn.hSurface = pSetSurfaceState->hSurface;
DxGetSurfaceState(&GetSurfaceStateIn, &GetSurfaceStateOut);
ASSERTDX(GetSurfaceStateOut.ddRVal == DD_OK,
"DxSetSurfaceState: Didn't expect failure from DxGetSurfaceState");
dwState = pSetSurfaceState->dwState;
// Get the video port if one is associated with the surface
if( peDxSurface->peDxVideoPort == NULL )
{
peDxVideoPort = NULL;
dwVPFlags = 0;
}
else
{
peDxVideoPort = peDxSurface->peDxVideoPort;
dwVPFlags = peDxVideoPort->dwVPFlags;
}
if ((dwState != DDSTATE_BOB) &&
(dwState != DDSTATE_WEAVE) &&
(dwState != DDSTATE_SKIPEVENFIELDS))
{
RIPDX("DxSetSurfaceState: Invalid dwState flags");
}
else if ((dwState & GetSurfaceStateOut.dwStateCaps) != dwState)
{
RIPDX("DxSetSurfaceState: State not supported");
}
else if ((dwState == DDSTATE_SKIPEVENFIELDS) && (peDxVideoPort == NULL ))
{
RIPDX("DxSetSurfaceState: Surface not attached to video port");
}
else if (((dwState & DDSTATE_BOB) &&
(peDxSurface->dwOverlayFlags & DDOVER_BOB)) ||
((dwState & DDSTATE_WEAVE) &&
!(peDxSurface->dwOverlayFlags & DDOVER_BOB) &&
!(dwVPFlags & (DDVP_SKIPEVENFIELDS|DDVP_SKIPODDFIELDS))) ||
((dwState & DDSTATE_SKIPEVENFIELDS ) &&
(dwVPFlags & (DDVP_SKIPEVENFIELDS|DDVP_SKIPODDFIELDS))))
{
// Don't do nothin, it's already in the requested state.
dwRet = DD_OK;
}
else if (peDxDirectDraw->DxApiInterface.DxSetState != NULL)
{
// Acquire the spinlock while we muck around in the 'dwSetStateState'
// and 'dwSetStateField' members, which are accessed by the videoport
// DPC.
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) ||
((peDxVideoPort != NULL) && (peDxVideoPort->bLost)) ||
(peDxSurface->bLost))
{
KdPrint(("DxSetSurfaceState: Objects are lost\n"));
dwRet = DDERR_SURFACELOST;
}
// If they want it to happen for the next field or we are not
// using a video port, call the mini port now; otherwise, we'll let
// the IRQ logoic handle this later.
else if ((pSetSurfaceState->dwStartField == 0) ||
(peDxVideoPort == NULL) ||
!(peDxVideoPort->bSoftwareAutoflip))
{
EffectStateChange( peDxVideoPort, peDxSurface, dwState );
}
else
{
peDxVideoPort->dwSetStateState = dwState;
peDxVideoPort->dwSetStateField = pSetSurfaceState->dwStartField;
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_NEW_STATE;
}
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
dwRet = DD_OK;
}
if (peDxDirectDraw->DxApiInterface.DxSetState == NULL)
{
dwRet = DDERR_UNSUPPORTED;
}
*pdwRet = dwRet;
}
}
/******************************Public*Routine******************************\
* VOID DxLock
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxLock(
DDLOCKIN* pLockIn,
DDLOCKOUT* pLockOut
)
{
DWORD dwRet;
DXOBJ* pDxObjDirectDraw;
DXOBJ* pDxObjSurface;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXSURFACE* peDxSurface;
DDLOCKININFO LockInInfo;
DDLOCKOUTINFO LockOutInfo;
KIRQL OldIrql;
pLockOut->ddRVal = DDERR_INVALIDPARAMS;
if (pLockIn == NULL)
{
return;
}
dwRet = DD_OK;
pDxObjDirectDraw = (DXOBJ*) pLockIn->hDirectDraw;
pDxObjSurface = (DXOBJ*) pLockIn->hSurface;
if ((pDxObjDirectDraw != NULL) &&
(pDxObjSurface != NULL))
{
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
peDxSurface = pDxObjSurface->peDxSurface;
ASSERTDX(peDxDirectDraw == peDxSurface->peDxDirectDraw,
"Surface and DirectDraw objects don't match");
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW,
"Invalid DirectDraw object");
ASSERTDX(pDxObjSurface->iDxType == DXT_SURFACE,
"Invalid surface object");
LockInInfo.lpSurfaceData = peDxSurface;
LockOutInfo.dwSurfacePtr = peDxSurface->fpLockPtr;
// The display driver can set 'fpLockPtr' to NULL in its SyncSurfaceData
// routine if it doesn't want to support a DXAPI lock.
if (peDxSurface->fpLockPtr == NULL)
{
KdPrint(("DxLock: Video miniport doesn't support lock on this surface\n"));
dwRet = DDERR_UNSUPPORTED;
}
else
{
// NOTE: The miniport should not wait for accelerator complete!
if (peDxDirectDraw->DxApiInterface.DxLock)
{
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) || (peDxSurface->bLost))
{
KdPrint(("DxLock: Objects are lost\n"));
dwRet = DDERR_SURFACELOST;
}
else
{
dwRet = peDxDirectDraw->DxApiInterface.DxLock(
peDxDirectDraw->HwDeviceExtension,
&LockInInfo,
&LockOutInfo);
}
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
if (dwRet != DD_OK)
{
KdPrint(("DxLock: Driver failed call\n"));
// Pass the return code on down...
}
}
pLockOut->lpSurface = (LPVOID) LockOutInfo.dwSurfacePtr;
pLockOut->dwSurfHeight = peDxSurface->dwHeight;
pLockOut->dwSurfWidth = peDxSurface->dwWidth;
pLockOut->lSurfPitch = peDxSurface->lPitch;
pLockOut->SurfaceCaps = peDxSurface->ddsCaps;
pLockOut->dwFormatFlags = peDxSurface->dwFormatFlags;
pLockOut->dwFormatFourCC = peDxSurface->dwFormatFourCC;
pLockOut->dwFormatBitCount = peDxSurface->dwFormatBitCount;
pLockOut->dwRBitMask = peDxSurface->dwRBitMask;
pLockOut->dwGBitMask = peDxSurface->dwGBitMask;
pLockOut->dwBBitMask = peDxSurface->dwBBitMask;
}
pLockOut->ddRVal = dwRet;
}
}
/******************************Public*Routine******************************\
* VOID DxFlipOverlay
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxFlipOverlay(
DDFLIPOVERLAY* pFlipOverlay,
DWORD* pdwRet
)
{
DWORD dwRet;
DXOBJ* pDxObjDirectDraw;
DXOBJ* pDxObjTarget;
DXOBJ* pDxObjCurrent;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXSURFACE* peDxTarget;
EDD_DXSURFACE* peDxCurrent;
DDFLIPOVERLAYINFO FlipOverlayInfo;
KIRQL OldIrql;
*pdwRet = DDERR_INVALIDPARAMS;
if (pFlipOverlay == NULL)
{
return;
}
dwRet = DDERR_UNSUPPORTED; // Assume failure
pDxObjDirectDraw = (DXOBJ*) pFlipOverlay->hDirectDraw;
pDxObjTarget = (DXOBJ*) pFlipOverlay->hTargetSurface;
pDxObjCurrent = (DXOBJ*) pFlipOverlay->hCurrentSurface;
if ((pDxObjDirectDraw != NULL) &&
(pDxObjTarget != NULL) &&
(pDxObjCurrent != NULL))
{
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
peDxTarget = pDxObjTarget->peDxSurface;
peDxCurrent = pDxObjCurrent->peDxSurface;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW,
"Invalid DirectDraw object");
ASSERTDX(pDxObjTarget->iDxType == DXT_SURFACE,
"Invalid target object");
ASSERTDX(pDxObjCurrent->iDxType == DXT_SURFACE,
"Invalid current object");
ASSERTDX((peDxDirectDraw == peDxTarget->peDxDirectDraw) &&
(peDxDirectDraw == peDxCurrent->peDxDirectDraw),
"Surface and DirectDraw objects don't match");
ASSERTDX((peDxCurrent->dwWidth == peDxTarget->dwWidth) &&
(peDxCurrent->dwHeight == peDxTarget->dwHeight),
"Surfaces are different sizes");
if (!(peDxCurrent->ddsCaps & DDSCAPS_OVERLAY) ||
(peDxCurrent->dwOverlayFlags & DDOVER_AUTOFLIP))
{
RIPDX("Invalid current overlay status");
}
else if (!(peDxTarget->ddsCaps & DDSCAPS_OVERLAY) ||
(peDxTarget->dwOverlayFlags & DDOVER_AUTOFLIP))
{
RIPDX("Invalid target overlay status");
}
else
{
FlipOverlayInfo.lpCurrentSurface = peDxCurrent;
FlipOverlayInfo.lpTargetSurface = peDxTarget;
FlipOverlayInfo.dwFlags = pFlipOverlay->dwFlags;
if (peDxDirectDraw->DxApiInterface.DxFlipOverlay)
{
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) ||
(peDxTarget->bLost) ||
(peDxCurrent->bLost))
{
KdPrint(("DxFlipOverlay: Objects are lost\n"));
dwRet = DDERR_SURFACELOST;
}
else
{
dwRet = peDxDirectDraw->DxApiInterface.DxFlipOverlay(
peDxDirectDraw->HwDeviceExtension,
&FlipOverlayInfo,
NULL);
}
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
}
if (dwRet != DD_OK)
{
KdPrint(("DxFlipOverlay: Driver failed call\n"));
}
}
*pdwRet = dwRet;
}
}
/******************************Public*Routine******************************\
* VOID DxFlipVideoPort
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxFlipVideoPort(
DDFLIPVIDEOPORT* pFlipVideoPort,
DWORD* pdwRet
)
{
DWORD dwRet;
DXOBJ* pDxObjDirectDraw;
DXOBJ* pDxObjVideoPort;
DXOBJ* pDxObjTarget;
DXOBJ* pDxObjCurrent;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXVIDEOPORT* peDxVideoPort;
EDD_DXSURFACE* peDxTarget;
EDD_DXSURFACE* peDxCurrent;
DDFLIPVIDEOPORTINFO FlipVideoPortInfo;
KIRQL OldIrql;
*pdwRet = DDERR_INVALIDPARAMS;
if (pFlipVideoPort == NULL)
{
return;
}
dwRet = DDERR_UNSUPPORTED; // Assume failure
pDxObjDirectDraw = (DXOBJ*) pFlipVideoPort->hDirectDraw;
pDxObjVideoPort = (DXOBJ*) pFlipVideoPort->hVideoPort;
pDxObjTarget = (DXOBJ*) pFlipVideoPort->hTargetSurface;
pDxObjCurrent = (DXOBJ*) pFlipVideoPort->hCurrentSurface;
if ((pDxObjDirectDraw != NULL) &&
(pDxObjVideoPort != NULL) &&
(pDxObjTarget != NULL) &&
(pDxObjCurrent != NULL))
{
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
peDxTarget = pDxObjTarget->peDxSurface;
peDxCurrent = pDxObjCurrent->peDxSurface;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW,
"Invalid DirectDraw object");
ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT,
"Invalid VideoPort object");
ASSERTDX(pDxObjTarget->iDxType == DXT_SURFACE,
"Invalid target object");
ASSERTDX(pDxObjCurrent->iDxType == DXT_SURFACE,
"Invalid current object");
ASSERTDX((peDxDirectDraw == peDxTarget->peDxDirectDraw) &&
(peDxDirectDraw == peDxCurrent->peDxDirectDraw) &&
(peDxDirectDraw == peDxVideoPort->peDxDirectDraw),
"Surface, VideoPort, and DirectDraw objects don't match");
ASSERTDX((peDxCurrent->dwWidth == peDxTarget->dwWidth) &&
(peDxCurrent->dwHeight == peDxTarget->dwHeight),
"Surfaces are different sizes");
ASSERTDX((pFlipVideoPort->dwFlags == DDVPFLIP_VIDEO) ||
(pFlipVideoPort->dwFlags == DDVPFLIP_VBI),
"Invalid flags");
ASSERTDX(!(peDxVideoPort->dwVPFlags & DDVP_AUTOFLIP),
"Flip not available while autoflipping");
FlipVideoPortInfo.lpVideoPortData = peDxVideoPort;
FlipVideoPortInfo.lpCurrentSurface = peDxCurrent;
FlipVideoPortInfo.lpTargetSurface = peDxTarget;
FlipVideoPortInfo.dwFlipVPFlags = pFlipVideoPort->dwFlags;
if (peDxDirectDraw->DxApiInterface.DxFlipVideoPort)
{
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) ||
(peDxVideoPort->bLost) ||
(peDxTarget->bLost) ||
(peDxCurrent->bLost))
{
KdPrint(("DxFlipVideoPort: Objects are lost\n"));
dwRet = DDERR_SURFACELOST;
}
else
{
dwRet = peDxDirectDraw->DxApiInterface.DxFlipVideoPort(
peDxDirectDraw->HwDeviceExtension,
&FlipVideoPortInfo,
NULL);
}
peDxCurrent->peDxVideoPort = NULL;
peDxTarget->peDxVideoPort = peDxVideoPort;
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
}
if (dwRet != DD_OK)
{
KdPrint(("DxFlipVideoPort: Driver failed call\n"));
}
*pdwRet = dwRet;
}
}
/******************************Public*Routine******************************\
* VOID DxGetCurrentAutoflip
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxGetCurrentAutoflip(
DDGETAUTOFLIPIN* pGetCurrentAutoflipIn,
DDGETAUTOFLIPOUT* pGetCurrentAutoflipOut
)
{
DWORD dwRet;
DXOBJ* pDxObjDirectDraw;
DXOBJ* pDxObjVideoPort;
DXOBJ* pDxObjTarget;
DXOBJ* pDxObjCurrent;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXVIDEOPORT* peDxVideoPort;
EDD_DXSURFACE* peDxTarget;
EDD_DXSURFACE* peDxCurrent;
DDGETPOLARITYININFO GetPolarityInInfo;
DDGETPOLARITYOUTINFO GetPolarityOutInfo;
DDGETCURRENTAUTOFLIPININFO GetCurrentAutoflipInInfo;
DDGETCURRENTAUTOFLIPOUTINFO GetCurrentAutoflipOutInfo;
KIRQL OldIrql;
DWORD dwVideo;
DWORD dwVBI;
BOOL bFlipping;
pGetCurrentAutoflipOut->ddRVal = DDERR_INVALIDPARAMS;
if (pGetCurrentAutoflipIn == NULL)
{
return;
}
dwRet = DDERR_UNSUPPORTED; // Assume failure
pDxObjDirectDraw = (DXOBJ*) pGetCurrentAutoflipIn->hDirectDraw;
pDxObjVideoPort = (DXOBJ*) pGetCurrentAutoflipIn->hVideoPort;
if ((pDxObjDirectDraw != NULL) &&
(pDxObjVideoPort != NULL))
{
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW,
"Invalid DirectDraw object");
ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT,
"Invalid VideoPort object");
ASSERTDX(peDxDirectDraw == peDxVideoPort->peDxDirectDraw,
"Surface, VideoPort, and DirectDraw objects don't match");
ASSERTDX(peDxVideoPort->dwVPFlags & DDVP_AUTOFLIP,
"Not currently autoflipping");
GetPolarityInInfo.lpVideoPortData = peDxVideoPort;
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) ||
(peDxVideoPort->bLost))
{
KdPrint(("DxGetCurrentAutoflip: Objects are lost\n"));
dwRet = DDERR_SURFACELOST;
}
else
{
dwRet = DDERR_UNSUPPORTED;
if (peDxDirectDraw->DxApiInterface.DxGetPolarity)
{
dwRet = peDxDirectDraw->DxApiInterface.DxGetPolarity(
peDxDirectDraw->HwDeviceExtension,
&GetPolarityInInfo,
&GetPolarityOutInfo);
}
if (dwRet != DD_OK)
{
KdPrint(("DxGetCurrentAutoflip: Driver failed GetPolarity\n"));
}
else
{
// Determine which field is currently receiving the data. If they
// are software autoflipping, I can do that myself; otherwise, I
// have to call the HAL
//
// When software autoflipping, there is an issue that if this
// function is called between the time that the IRQ occured
// and the time that the DPC ran, this function would return
// the wrong surface. Since fixing this requires that we do all
// of the work at IRQ time (bad), we can probably assume that
// this will always be the case since anybody using this
// function would be calling it during the IRQ callback. We
// will therefore work around it.
dwVideo = (DWORD) -1;
dwVBI = (DWORD) -1;
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP )
{
dwVideo = peDxVideoPort->iCurrentVideo;
bFlipping = TRUE;
if( ( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_SKIP_SET ) &&
( peDxVideoPort->dwFieldToSkip == 1 ) )
{
bFlipping = FALSE;
}
else if( !( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_SKIPPED_LAST ) &&
( peDxVideoPort->dwVPFlags & DDVP_INTERLEAVE ) &&
!( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_FLIP_NEXT ) )
{
bFlipping = FALSE;
}
if( bFlipping )
{
if( ++dwVideo >= peDxVideoPort->cAutoflipVideo )
{
dwVideo = 0;
}
}
}
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI )
{
dwVBI = peDxVideoPort->iCurrentVbi;
if( ( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_VBI_INTERLEAVED ) &&
!( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_FLIP_NEXT_VBI ) )
{
if( ++dwVBI >= peDxVideoPort->cAutoflipVbi )
{
dwVBI = 0;
}
}
}
if( ( dwVideo == (DWORD) -1 ) && ( dwVBI == (DWORD) -1 ) )
{
GetCurrentAutoflipInInfo.lpVideoPortData = peDxVideoPort;
GetCurrentAutoflipOutInfo.dwSurfaceIndex = 0;
GetCurrentAutoflipOutInfo.dwVBISurfaceIndex = 0;
if (peDxDirectDraw->DxApiInterface.DxGetCurrentAutoflip)
{
dwRet = peDxDirectDraw->DxApiInterface.DxGetCurrentAutoflip(
peDxDirectDraw->HwDeviceExtension,
&GetCurrentAutoflipInInfo,
&GetCurrentAutoflipOutInfo);
}
dwVideo = GetCurrentAutoflipOutInfo.dwSurfaceIndex;
dwVBI = GetCurrentAutoflipOutInfo.dwVBISurfaceIndex;
}
pGetCurrentAutoflipOut->hVideoSurface = NULL;
pGetCurrentAutoflipOut->hVBISurface = NULL;
if( ( peDxVideoPort->cAutoflipVideo > 0 ) && ( dwVideo != (DWORD) -1 ) )
{
pGetCurrentAutoflipOut->hVideoSurface =
peDxVideoPort->apeDxSurfaceVideo[dwVideo];
}
if( ( peDxVideoPort->cAutoflipVbi > 0 ) && ( dwVBI != (DWORD) -1 ) )
{
pGetCurrentAutoflipOut->hVBISurface =
peDxVideoPort->apeDxSurfaceVbi[dwVBI];
}
pGetCurrentAutoflipOut->bPolarity = GetPolarityOutInfo.bPolarity;
}
}
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
pGetCurrentAutoflipOut->ddRVal = dwRet;
}
}
/******************************Public*Routine******************************\
* VOID DxGetPreviousAutoflip
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxGetPreviousAutoflip(
DDGETAUTOFLIPIN* pGetPreviousAutoflipIn,
DDGETAUTOFLIPOUT* pGetPreviousAutoflipOut
)
{
DWORD dwRet;
DXOBJ* pDxObjDirectDraw;
DXOBJ* pDxObjVideoPort;
DXOBJ* pDxObjTarget;
DXOBJ* pDxObjCurrent;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXVIDEOPORT* peDxVideoPort;
EDD_DXSURFACE* peDxTarget;
EDD_DXSURFACE* peDxPrevious;
DDGETPOLARITYININFO GetPolarityInInfo;
DDGETPOLARITYOUTINFO GetPolarityOutInfo;
DDGETPREVIOUSAUTOFLIPININFO GetPreviousAutoflipInInfo;
DDGETPREVIOUSAUTOFLIPOUTINFO GetPreviousAutoflipOutInfo;
KIRQL OldIrql;
DWORD dwVideo;
DWORD dwVBI;
pGetPreviousAutoflipOut->ddRVal = DDERR_INVALIDPARAMS;
if (pGetPreviousAutoflipIn == NULL)
{
return;
}
dwRet = DDERR_UNSUPPORTED; // Assume failure
pDxObjDirectDraw = (DXOBJ*) pGetPreviousAutoflipIn->hDirectDraw;
pDxObjVideoPort = (DXOBJ*) pGetPreviousAutoflipIn->hVideoPort;
if ((pDxObjDirectDraw != NULL) &&
(pDxObjVideoPort != NULL))
{
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW,
"Invalid DirectDraw object");
ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT,
"Invalid VideoPort object");
ASSERTDX(peDxDirectDraw == peDxVideoPort->peDxDirectDraw,
"Surface, VideoPort, and DirectDraw objects don't match");
ASSERTDX(peDxVideoPort->dwVPFlags & DDVP_AUTOFLIP,
"Not currently autoflipping");
GetPolarityInInfo.lpVideoPortData = peDxVideoPort;
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) ||
(peDxVideoPort->bLost))
{
KdPrint(("DxGetPreviousAutoflip: Objects are lost\n"));
dwRet = DDERR_SURFACELOST;
}
else
{
dwRet = DDERR_UNSUPPORTED;
if (peDxDirectDraw->DxApiInterface.DxGetPolarity)
{
dwRet = peDxDirectDraw->DxApiInterface.DxGetPolarity(
peDxDirectDraw->HwDeviceExtension,
&GetPolarityInInfo,
&GetPolarityOutInfo);
}
if (dwRet != DD_OK)
{
KdPrint(("DxGetPreviousAutoflip: Driver failed GetPolarity\n"));
}
else
{
// Determine which field is currently receiving the data. If they
// are software autoflipping, I can do that myself; otherwise, I
// have to call the HAL
//
// This is complicated by the facts that:
// 1) Skipping may be enabled.
// 3) When interleaving, they flip every other field, but its not
// guarenteed that the flip always occurs between the even and the
// odd fields.
//
// When software autoflipping, there is an issue that if this
// function is called between the time that the IRQ occured
// and the time that the DPC ran, this function would return
// the wrong surface. Since fixing this requires that we do all
// of the work at IRQ time (bad), we can probably assume that
// this will always be the case since anybody using this
// function would be calling it during the IRQ callback. We
// will therefore work around it.
dwVideo = (DWORD) -1;
dwVBI = (DWORD) -1;
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP )
{
dwVideo = peDxVideoPort->iCurrentVideo;
}
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI )
{
dwVBI = peDxVideoPort->iCurrentVbi;
}
if( ( dwVideo == (DWORD) -1 ) && ( dwVBI == (DWORD) -1 ) )
{
GetPreviousAutoflipInInfo.lpVideoPortData = peDxVideoPort;
GetPreviousAutoflipOutInfo.dwSurfaceIndex = 0;
GetPreviousAutoflipOutInfo.dwVBISurfaceIndex = 0;
if (peDxDirectDraw->DxApiInterface.DxGetPreviousAutoflip)
{
dwRet = peDxDirectDraw->DxApiInterface.DxGetPreviousAutoflip(
peDxDirectDraw->HwDeviceExtension,
&GetPreviousAutoflipInInfo,
&GetPreviousAutoflipOutInfo);
}
dwVideo = GetPreviousAutoflipOutInfo.dwSurfaceIndex;
dwVBI = GetPreviousAutoflipOutInfo.dwVBISurfaceIndex;
}
pGetPreviousAutoflipOut->hVideoSurface = NULL;
pGetPreviousAutoflipOut->hVBISurface = NULL;
if( ( peDxVideoPort->cAutoflipVideo > 0 ) && ( dwVideo != (DWORD) -1 ) )
{
pGetPreviousAutoflipOut->hVideoSurface =
peDxVideoPort->apeDxSurfaceVideo[dwVideo];
}
if( ( peDxVideoPort->cAutoflipVbi > 0 ) && ( dwVBI != (DWORD) -1 ) )
{
pGetPreviousAutoflipOut->hVBISurface =
peDxVideoPort->apeDxSurfaceVbi[dwVBI];
}
pGetPreviousAutoflipOut->bPolarity =
( GetPolarityOutInfo.bPolarity == FALSE ); // invert
}
}
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
pGetPreviousAutoflipOut->ddRVal = dwRet;
}
}
/******************************Public*Routine******************************\
* BOOL bDxModifyPassiveEventList
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
bDxModifyPassiveEventList(
EDD_DXDIRECTDRAW* peDxDirectDraw,
BOOL bAdd, // TRUE to add, FALSE to delete
DWORD dwEvent,
LPDD_NOTIFYCALLBACK pfnCallBack,
PVOID pContext
)
{
BOOL bRet;
DXAPI_EVENT* pDxEvent;
DXAPI_EVENT* pDxEvent_New;
DXAPI_EVENT* pDxEvent_Previous;
KIRQL OldIrql;
bRet = FALSE; // Assume failure
ASSERTDX(KeGetCurrentIrql() == PASSIVE_LEVEL, "Expected passive level");
ASSERTDX((bAdd == FALSE) || (bAdd == TRUE), "Bad boolean");
if (bAdd)
{
pDxEvent_New = (DXAPI_EVENT*) ExAllocatePoolWithTag(PagedPool,
sizeof(*pDxEvent),
'eddG');
if (pDxEvent_New == NULL)
return(FALSE);
RtlZeroMemory(pDxEvent_New, sizeof(*pDxEvent_New));
}
// We must synchronize additions or deletions to the passive-level
// event list via our devlock.
ASSERTDX(gpfnLockDevice, "bDxModifyPassiveEventList: gpfnLockDevice is NULL");
gpfnLockDevice(peDxDirectDraw->hdev);
if (peDxDirectDraw->bLost)
{
KdPrint(("bDxModifyPassiveEventList: Object is lost\n"));
}
else
{
// First, try to find this event in the list:
pDxEvent_Previous = NULL;
for (pDxEvent = peDxDirectDraw->pDxEvent_PassiveList;
pDxEvent != NULL;
pDxEvent = pDxEvent->pDxEvent_Next)
{
if ((pDxEvent->dwEvent == dwEvent) &&
(pDxEvent->pfnCallBack == pfnCallBack) &&
(pDxEvent->pContext == pContext))
{
break;
}
pDxEvent_Previous = pDxEvent;
}
// It's a failure when:
//
// 1) If adding, the same event is already in the list;
// 2) If deleting, the event is not in the list.
if ((bAdd) == (pDxEvent == NULL))
{
if (bAdd)
{
// Add the event.
pDxEvent_New->peDxDirectDraw = peDxDirectDraw;
pDxEvent_New->dwEvent = dwEvent;
pDxEvent_New->dwIrqFlag = 0;
pDxEvent_New->pfnCallBack = pfnCallBack;
pDxEvent_New->pContext = pContext;
pDxEvent_New->pDxEvent_Next = peDxDirectDraw->pDxEvent_PassiveList;
peDxDirectDraw->pDxEvent_PassiveList = pDxEvent_New;
bRet = TRUE;
}
else
{
// Delete the event.
if (pDxEvent_Previous == NULL)
{
ASSERTDX(peDxDirectDraw->pDxEvent_PassiveList == pDxEvent,
"Deletion code is confused");
peDxDirectDraw->pDxEvent_PassiveList = pDxEvent->pDxEvent_Next;
}
else
{
pDxEvent_Previous->pDxEvent_Next = pDxEvent->pDxEvent_Next;
}
bRet = TRUE;
}
}
}
ASSERTDX(gpfnUnlockDevice, "bDxModifyPassiveEventList: gpfnUnlockDevice is NULL");
gpfnUnlockDevice(peDxDirectDraw->hdev);
if (bAdd) // Add case
{
if (!bRet)
{
// Add failed, so free the new node we allocated up front:
ExFreePool(pDxEvent_New);
RIPDX("DD_DXAPI_REGISTER_EVENT: Event was already registered");
}
}
else // Remove case
{
if (bRet)
{
// Delete succeeded, so free the old node:
ExFreePool(pDxEvent);
}
else
{
KdPrint(("DD_DXAPI_UNREGISTEREVENT: Couldn't find an event registered with those\n"));
KdPrint(("same parameters, so the unregister failed.\n"));
RIPDX("This will probably cause a leak of non-paged memory!");
}
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL bDxModifyDispatchEventList
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
bDxModifyDispatchEventList(
EDD_DXDIRECTDRAW* peDxDirectDraw,
EDD_DXVIDEOPORT* peDxVideoPort,
BOOL bAdd, // TRUE to add, FALSE to delete
DWORD dwEvent,
DWORD dwIrqFlag,
LPDD_NOTIFYCALLBACK pfnCallBack,
PVOID pContext,
DWORD dwListEntry
)
{
BOOL bRet;
DXAPI_EVENT* pDxEvent;
DXAPI_EVENT* pDxEvent_New;
DXAPI_EVENT* pDxEvent_Previous;
KIRQL OldIrql;
bRet = FALSE; // Assume failure
ASSERTDX(KeGetCurrentIrql() == PASSIVE_LEVEL, "Expected passive level");
ASSERTDX((bAdd == FALSE) || (bAdd == TRUE), "Bad boolean");
// The event list is traversed at dispatch-level, so needs
// to be allocated non-paged.
if (bAdd)
{
pDxEvent_New = (DXAPI_EVENT*) ExAllocatePoolWithTag(NonPagedPool,
sizeof(*pDxEvent),
'eddG');
if (pDxEvent_New == NULL)
return(FALSE);
RtlZeroMemory(pDxEvent_New, sizeof(*pDxEvent_New));
}
// We must synchronize additions or deletions to the dispatch-level
// event list via our spin lock. Note that this spinlock (of course)
// raises our IRQL level, which means we can't touch any pageable code!
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) ||
((peDxVideoPort != NULL) && (peDxVideoPort->bLost)))
{
KdPrint(("bDxModifyDispatchEventList: Objects are lost\n"));
}
else
{
// First, try to find this event in the list:
pDxEvent_Previous = NULL;
for (pDxEvent = peDxDirectDraw->pDxEvent_DispatchList[dwListEntry];
pDxEvent != NULL;
pDxEvent = pDxEvent->pDxEvent_Next)
{
if ((pDxEvent->dwEvent == dwEvent) &&
(pDxEvent->dwIrqFlag == dwIrqFlag) &&
(pDxEvent->pfnCallBack == pfnCallBack) &&
(pDxEvent->pContext == pContext))
{
break;
}
pDxEvent_Previous = pDxEvent;
}
// It's a failure when:
//
// 1) If adding, the same event is already in the list;
// 2) If deleting, the event is not in the list.
if ((bAdd) == (pDxEvent == NULL))
{
if (bAdd)
{
// Add the event.
pDxEvent_New->peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
pDxEvent_New->peDxVideoPort = peDxVideoPort;
pDxEvent_New->dwEvent = dwEvent;
pDxEvent_New->dwIrqFlag = dwIrqFlag;
pDxEvent_New->pfnCallBack = pfnCallBack;
pDxEvent_New->pContext = pContext;
pDxEvent_New->pDxEvent_Next = peDxDirectDraw->pDxEvent_DispatchList[dwListEntry];
peDxDirectDraw->pDxEvent_DispatchList[dwListEntry] = pDxEvent_New;
bRet = TRUE;
}
else
{
// Delete the event.
if (pDxEvent_Previous == NULL)
{
ASSERTDX(peDxDirectDraw->pDxEvent_DispatchList[dwListEntry] == pDxEvent,
"Deletion code is confused");
peDxDirectDraw->pDxEvent_DispatchList[dwListEntry]
= pDxEvent->pDxEvent_Next;
}
else
{
pDxEvent_Previous->pDxEvent_Next = pDxEvent->pDxEvent_Next;
}
bRet = TRUE;
}
}
}
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
if (bAdd) // Add case
{
if (!bRet)
{
// Add failed, so free the new node we allocated up front:
ExFreePool(pDxEvent_New);
}
}
else // Remove case
{
if (bRet)
{
// Delete succeeded, so free the old node:
ExFreePool(pDxEvent);
}
else
{
KdPrint(("DD_DXAPI_UNREGISTEREVENT: Couldn't find an event registered with those\n"));
KdPrint(("same parameters, so the unregister failed.\n"));
RIPDX("This will probably cause a leak of non-paged memory!");
}
}
return(bRet);
}
/******************************Public*Routine******************************\
* VOID vDxEnableInterrupts
*
* NOTE: Drivers may not fail DxEnableIrq.
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
vDxEnableInterrupts(
EDD_DXDIRECTDRAW* peDxDirectDraw,
DWORD dwLine
)
{
DWORD dwIRQSources = 0;
KIRQL OldIrql;
DXAPI_EVENT* pDxEvent;
DDENABLEIRQINFO EnableIrqInfo;
DWORD dwRet;
DWORD i;
ASSERTDX(KeGetCurrentIrql() == PASSIVE_LEVEL, "Expected passive level");
ASSERTDX(peDxDirectDraw->DxApiInterface.DxEnableIrq != NULL,
"DxEnableIrq must be hooked if supporting interrupts.");
// We acquire both the devlock and the spinlock to ensure that no other
// activity in the driver is occurring while interrupts are enabled.
//
// The motivation for acquiring both (the spinlock could have been
// sufficient) is that we want to allow drivers to touch the CRTC
// registers in their interrupt enable routine (typically, both the
// display driver and the enable interrupt routine use CRTC registers,
// the usage of which must be synchronized).
ASSERTDX(gpfnLockDevice, "vDxEnableInterrupts: gpfnLockDevice is NULL");
gpfnLockDevice(peDxDirectDraw->hdev);
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
// Compute the interrupts that are to be enabled by traversing the
// active event list:
for( i = 0; i < NUM_DISPATCH_LISTS; i++ )
{
for (pDxEvent = peDxDirectDraw->pDxEvent_DispatchList[i];
pDxEvent != NULL;
pDxEvent = pDxEvent->pDxEvent_Next)
{
dwIRQSources |= pDxEvent->dwIrqFlag;
}
}
EnableIrqInfo.dwIRQSources = dwIRQSources;
EnableIrqInfo.dwLine = dwLine;
EnableIrqInfo.IRQCallback = DxIrqCallBack;
EnableIrqInfo.lpIRQData = &peDxDirectDraw->IrqData;
dwRet = peDxDirectDraw->DxApiInterface.DxEnableIrq(
peDxDirectDraw->HwDeviceExtension,
&EnableIrqInfo,
NULL);
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
ASSERTDX(gpfnUnlockDevice, "vDxEnableInterrupts: gpfnUnlockDevice is NULL");
gpfnUnlockDevice(peDxDirectDraw->hdev);
ASSERTDX(dwRet == DD_OK, "vDxEnableInterrupts: Driver failed DxEnableIrq");
}
/******************************Public*Routine******************************\
* DWORD dwDxRegisterEvent
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD
dwDxRegisterEvent(
DDREGISTERCALLBACK* pRegisterEvent,
BOOL bRegister // TRUE if register, FALSE if unregister
)
{
DWORD dwRet;
DXOBJ* pDxObjDirectDraw;
DXOBJ* pDxObjVideoPort;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXVIDEOPORT* peDxVideoPort;
DWORD dwEvent;
DWORD dwIrqFlag;
BOOL bPassiveEvent;
BOOL bDispatchEvent;
DWORD dwLine;
dwRet = DDERR_GENERIC; // Assume failure
// Passive level is required because we have to acquire the devlock
// for the RESCHANGE and DOSBOX notifications.
ASSERTDX(KeGetCurrentIrql() == PASSIVE_LEVEL, "Expected passive level");
ASSERTDX(pRegisterEvent->pfnCallback != NULL, "Null callback specified");
ASSERTDX(pRegisterEvent->hDirectDraw != NULL, "Null hDirectDraw specified");
pDxObjDirectDraw = (DXOBJ*) pRegisterEvent->hDirectDraw;
if (pDxObjDirectDraw != NULL)
{
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
// Note that we don't support the hooking of DDEVENT_CLOSEDIRECTDRAW,
// DDEVENT_CLOSESURFACE, or DDEVENT_CLOSEVIDEOPORT because those are
// always explictly registered with the object open call. If multiple
// clients want object close notification, they should each open their
// own object instances.
dwEvent = pRegisterEvent->dwEvents;
// Memphis doesn't bother checking to verify that 'dwParam1' and
// 'dwParam2' are zero when unused, so we won't either.
bPassiveEvent = FALSE;
bDispatchEvent = FALSE;
peDxVideoPort = NULL;
dwLine = 0;
dwIrqFlag = 0;
switch (dwEvent)
{
case DDEVENT_VP_VSYNC:
case DDEVENT_VP_LINE:
ASSERTDX(pRegisterEvent->dwParam1 != NULL,
"dwParam1 should be videoport handle");
pDxObjVideoPort = (DXOBJ*) pRegisterEvent->dwParam1;
if (pDxObjVideoPort != NULL)
{
peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT,
"dwParam1 should be videoport handle");
if (dwEvent == DDEVENT_VP_LINE)
{
dwIrqFlag = DDIRQ_VPORT0_LINE; // We're going to shift this...
// We make it so that the 'dwLine' parameter is non-zero only
// when the event is registered, not unregistered,
dwLine = (bRegister) ? (DWORD) pRegisterEvent->dwParam2 : 0;
}
else
{
dwIrqFlag = DDIRQ_VPORT0_VSYNC; // We're going to shift this...
}
dwIrqFlag <<= (2 * peDxVideoPort->dwVideoPortID);
bDispatchEvent = TRUE;
}
break;
case DDEVENT_DISPLAY_VSYNC:
dwIrqFlag = DDIRQ_DISPLAY_VSYNC;
bDispatchEvent = TRUE;
break;
case DDEVENT_PRERESCHANGE:
case DDEVENT_POSTRESCHANGE:
case DDEVENT_PREDOSBOX:
case DDEVENT_POSTDOSBOX:
bPassiveEvent = TRUE;
break;
default:
KdPrint(("dwDxRegisterEvent: Invalid dwEvents specified\n"));
dwRet = DDERR_UNSUPPORTED;
break;
}
if (bPassiveEvent)
{
if (bDxModifyPassiveEventList(peDxDirectDraw,
bRegister,
dwEvent,
pRegisterEvent->pfnCallback,
pRegisterEvent->pContext))
{
dwRet = DD_OK;
}
}
else if (bDispatchEvent)
{
// First, verify that the requested interrupt is supported:
if (!(peDxDirectDraw->dwIRQCaps & dwIrqFlag))
{
KdPrint(("dwDxRegisterEvent: Interrupt not supported by driver.\n"));
dwRet = DDERR_UNSUPPORTED;
}
else
{
if (bDxModifyDispatchEventList(peDxDirectDraw,
peDxVideoPort,
bRegister,
dwEvent,
dwIrqFlag,
pRegisterEvent->pfnCallback,
pRegisterEvent->pContext,
CLIENT_DISPATCH_LIST))
{
vDxEnableInterrupts(peDxDirectDraw, dwLine);
dwRet = DD_OK;
}
}
}
}
return(dwRet);
}
/******************************Public*Routine******************************\
* VOID DxRegisterEvent
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxRegisterEvent(
DDREGISTERCALLBACK* pRegisterEvent,
DWORD* pdwRet
)
{
if (pRegisterEvent == NULL)
{
*pdwRet = DDERR_INVALIDPARAMS;
}
else
{
*pdwRet = dwDxRegisterEvent(pRegisterEvent, TRUE);
}
}
/******************************Public*Routine******************************\
* VOID DxUnregisterEvent
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxUnregisterEvent(
DDREGISTERCALLBACK* pRegisterEvent,
DWORD* pdwRet
)
{
if (pRegisterEvent == NULL)
{
*pdwRet = DDERR_INVALIDPARAMS;
}
else
{
*pdwRet = dwDxRegisterEvent(pRegisterEvent, FALSE);
}
}
/******************************Public*Routine******************************\
* VOID DxGetPolarity
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxGetPolarity(
DDGETPOLARITYIN* pGetPolarityIn,
DDGETPOLARITYOUT* pGetPolarityOut
)
{
DWORD dwRet;
DXOBJ* pDxObjDirectDraw;
DXOBJ* pDxObjVideoPort;
DXOBJ* pDxObjTarget;
DXOBJ* pDxObjCurrent;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXVIDEOPORT* peDxVideoPort;
DDGETPOLARITYININFO GetPolarityInInfo;
DDGETPOLARITYOUTINFO GetPolarityOutInfo;
KIRQL OldIrql;
pGetPolarityOut->ddRVal = DDERR_INVALIDPARAMS;
if (pGetPolarityIn == NULL)
{
return;
}
dwRet = DDERR_UNSUPPORTED; // Assume failure
pDxObjDirectDraw = (DXOBJ*) pGetPolarityIn->hDirectDraw;
pDxObjVideoPort = (DXOBJ*) pGetPolarityIn->hVideoPort;
if ((pDxObjDirectDraw != NULL) &&
(pDxObjVideoPort != NULL))
{
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
ASSERTDX(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW,
"Invalid DirectDraw object");
ASSERTDX(pDxObjVideoPort->iDxType == DXT_VIDEOPORT,
"Invalid VideoPort object");
ASSERTDX(peDxDirectDraw == peDxVideoPort->peDxDirectDraw,
"Surface, VideoPort, and DirectDraw objects don't match");
GetPolarityInInfo.lpVideoPortData = peDxVideoPort;
GetPolarityOutInfo.bPolarity = 0;
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if ((peDxDirectDraw->bLost) ||
(peDxVideoPort->bLost))
{
KdPrint(("DxGetPolarity: Objects are lost\n"));
dwRet = DDERR_SURFACELOST;
}
else
{
if (peDxDirectDraw->DxApiInterface.DxGetPolarity)
{
dwRet = peDxDirectDraw->DxApiInterface.DxGetPolarity(
peDxDirectDraw->HwDeviceExtension,
&GetPolarityInInfo,
&GetPolarityOutInfo);
}
}
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
pGetPolarityOut->ddRVal = dwRet;
pGetPolarityOut->bPolarity = GetPolarityOutInfo.bPolarity;
}
}
/******************************Public*Routine******************************\
* VOID DxAddVpCaptureBuffer
*
* 01-Nov-1997 -by- smac
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxAddVpCaptureBuffer(
DDADDVPCAPTUREBUFF* pAddCaptureBuff,
DWORD* pdwRet
)
{
DXOBJ* pDxObjCapture;
EDD_DXCAPTURE* peDxCapture;
EDD_DXVIDEOPORT* peDxVideoPort;
EDD_DXDIRECTDRAW* peDxDirectDraw;
DWORD dwTop;
KIRQL OldIrql;
*pdwRet = DDERR_INVALIDPARAMS;
if (pAddCaptureBuff == NULL)
{
return;
}
pDxObjCapture = (DXOBJ*) pAddCaptureBuff->hCapture;
if (pDxObjCapture != NULL)
{
peDxCapture = pDxObjCapture->peDxCapture;
ASSERTDX(pDxObjCapture->iDxType == DXT_CAPTURE,
"Invalid Capture object");
ASSERTDX(pAddCaptureBuff->pKEvent != NULL,
"No KEvent specified");
ASSERTDX(pAddCaptureBuff->pMDL != NULL,
"No MDL specified");
ASSERTDX((pAddCaptureBuff->dwFlags != 0 ) &&
!(pAddCaptureBuff->dwFlags & ~(DDADDBUFF_SYSTEMMEMORY|DDADDBUFF_NONLOCALVIDMEM|DDADDBUFF_INVERT)),
"Invalid flags specified");
ASSERTDX(pAddCaptureBuff->lpBuffInfo != NULL,
"lpBuffInfo not specified");
*pdwRet = DDERR_INVALIDOBJECT;
peDxVideoPort = peDxCapture->peDxVideoPort;
if( peDxVideoPort != NULL )
{
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
if( !( peDxVideoPort->bLost ) &&
!( peDxCapture->bLost ) )
{
// Is the queue full?
dwTop = peDxCapture->dwTop;
if( ( peDxCapture->CaptureQueue[dwTop].flFlags & DD_DXCAPTUREBUFF_FLAG_IN_USE ) ||
!( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_ON ) )
{
*pdwRet = DDERR_CURRENTLYNOTAVAIL;
}
else
{
// Save the new buffer in the queque
peDxCapture->CaptureQueue[dwTop].dwClientFlags =
pAddCaptureBuff->dwFlags;
peDxCapture->CaptureQueue[dwTop].pBuffMDL =
pAddCaptureBuff->pMDL;
peDxCapture->CaptureQueue[dwTop].pBuffKEvent =
pAddCaptureBuff->pKEvent;
peDxCapture->CaptureQueue[dwTop].lpBuffInfo =
(PVOID) pAddCaptureBuff->lpBuffInfo;
peDxCapture->CaptureQueue[dwTop].flFlags = DD_DXCAPTUREBUFF_FLAG_IN_USE;
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_CAPTURING;
if( ++(peDxCapture->dwTop) >= DXCAPTURE_MAX_CAPTURE_BUFFS )
{
peDxCapture->dwTop = 0;
}
*pdwRet = DD_OK;
}
}
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
}
}
}
/******************************Public*Routine******************************\
* VOID DxInternalFlushVpCaptureBuffs
*
* 12-Apr-1999 -by- smac
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxInternalFlushVpCaptureBuffs(
EDD_DXDIRECTDRAW* peDxDirectDraw,
EDD_DXVIDEOPORT* peDxVideoPort,
EDD_DXCAPTURE* peDxCapture
)
{
DDTRANSFERININFO ddTransferIn;
DDTRANSFEROUTINFO ddTransferOut;
LPDDCAPBUFFINFO lpBuffInfo;
DWORD i;
// Turn off all video port capture if nobody else is capturing
if( peDxVideoPort->peDxCapture && ( peDxCapture->peDxCaptureNext == NULL ) )
{
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_CAPTURING;
}
// If a buffer is in the queue and the busmaster has not yet been
// initiated, clear it now so we don't do it. If the busmaster has
// already been initiated, we will tell the miniport to stop it now.
peDxCapture->dwTop = peDxCapture->dwBottom = 0;
for( i = 0; i < DXCAPTURE_MAX_CAPTURE_BUFFS; i++ )
{
if( peDxCapture->CaptureQueue[i].flFlags & DD_DXCAPTUREBUFF_FLAG_IN_USE )
{
if( peDxCapture->CaptureQueue[i].flFlags & DD_DXCAPTUREBUFF_FLAG_WAITING )
{
ddTransferIn.dwStartLine = 0;
ddTransferIn.dwEndLine = 0;
ddTransferIn.dwTransferFlags = DDTRANSFER_CANCEL;
ddTransferIn.lpDestMDL = NULL;
ddTransferIn.lpSurfaceData = NULL;
ddTransferIn.dwTransferID = ((ULONG_PTR)peDxCapture & ~0xf) + i;
if (peDxDirectDraw->DxApiInterface.DxTransfer)
{
peDxDirectDraw->DxApiInterface.DxTransfer(
peDxDirectDraw->HwDeviceExtension,
&ddTransferIn,
&ddTransferOut);
}
peDxCapture->CaptureQueue[i].peDxSurface->flFlags
&= ~DD_DXSURFACE_FLAG_TRANSFER;
}
lpBuffInfo = (LPDDCAPBUFFINFO) peDxCapture->CaptureQueue[i].lpBuffInfo;
lpBuffInfo->bPolarity = 0;
lpBuffInfo->dwFieldNumber = 0;
lpBuffInfo->ddRVal = (DWORD) DDERR_GENERIC;
peDxCapture->CaptureQueue[i].flFlags = 0;
KeSetEvent( peDxCapture->CaptureQueue[i].pBuffKEvent, 0, 0 );
}
}
}
/******************************Public*Routine******************************\
* VOID DxFlushVpCaptureBuffs
*
* 01-Nov-1997 -by- smac
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxFlushVpCaptureBuffs(
DWORD** hCapture,
DWORD* pdwRet
)
{
DXOBJ* pDxObjCapture;
EDD_DXCAPTURE* peDxCapture;
EDD_DXVIDEOPORT* peDxVideoPort;
EDD_DXDIRECTDRAW* peDxDirectDraw;
KIRQL OldIrql;
*pdwRet = DDERR_INVALIDPARAMS;
if (hCapture == NULL)
{
return;
}
ASSERTDX(KeGetCurrentIrql() <= DISPATCH_LEVEL,
"DxFlushCaptureBuffs: Call less than or equl to DISPATCH_LEVEL (it accesses the dispatch table)");
pDxObjCapture = (DXOBJ*) (*hCapture);
if (pDxObjCapture != NULL)
{
peDxCapture = pDxObjCapture->peDxCapture;
peDxVideoPort = peDxCapture->peDxVideoPort;
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
DxInternalFlushVpCaptureBuffs( peDxDirectDraw, peDxVideoPort, peDxCapture );
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
*pdwRet = DD_OK;
}
}
/******************************Public*Routine******************************\
* VOID DxIrqCallBack
*
* This routine is called by the miniport at interrupt time to notify us
* of interrupt-based events. We simply queue a DPC to handle the request
* at the more appropriate dispatch level, instead of interrupt level that
* we're currently at.
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxIrqCallBack(
DX_IRQDATA* pIrqData
)
{
EDD_DXDIRECTDRAW* peDxDirectDraw;
// We always tell the miniport to call us back with the pointer to
// &peDxDirectDraw->IrqData, so we can get back to the original
// peDxDirectDraw by subtracting the offset. If we ever need to
// change this in the future, we can simply add a field to DX_IRQDATA
// to point to the context:
peDxDirectDraw = (EDD_DXDIRECTDRAW*)
((BYTE*) pIrqData - offsetof(EDD_DXDIRECTDRAW, IrqData));
// It's okay if KeInsertQueueDpc fails because the same DPC for a
// previous interrupt is still queued -- the miniport always ORs
// its interrupt flags into pIrqData->dwIrqflags.
KeInsertQueueDpc(&peDxDirectDraw->EventDpc, pIrqData, NULL);
}
/******************************Public*Routine******************************\
* VOID DxGetIrqFlags
*
* Out interrupt processing code runs at DPC level, and can be interrupt
* by an ISR. Consequently, when we look at the interrupt status, we
* must synchronize with the ISR. This is accomplished by having
* VideoPortSynchronizeExecution (which does a KeSynchronizeExecution)
* call-back to this routine.
*
* All we do here is copy the flags to the device extension (actually,
* we use the EDD_DXDIRECTDRAW which is allocated one-to-one with the
* device extension).
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOLEAN
DxGetIrqFlags(
PVOID pvContext
)
{
EDD_DXDIRECTDRAW* peDxDirectDraw;
peDxDirectDraw = (EDD_DXDIRECTDRAW*) pvContext;
// Copy the flags to a safe place:
peDxDirectDraw->dwSynchedIrqFlags = peDxDirectDraw->IrqData.dwIrqFlags;
// We have to zero the current flags because the miniport always ORs
// its flags in:
peDxDirectDraw->IrqData.dwIrqFlags = 0;
return(TRUE);
}
/******************************Public*Routine******************************\
* VOID DxEventDpc
*
* This routine does all the work of handling interrupt notification
* from the miniport. It makes the synchronous call-backs to anyone
* who has hooked the particular event.
*
* Note that to be synchronous we're making the call-backs at dispatch
* level. So if a callee doesn't require a truly synchronous notification,
* they should do nothing but kick off an event.
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
// We can't call KeSynchronizeExecution directly, because we don't
// have the device's interrupt object. Videoport.sys does, however.
// Unfortunately, 'video.h', which is used to access the videoport.sys
// routines, was never intended to be mixed with GDI and USER header
// files (among other problems, there are conflicts in the PEVENT and
// PVIDEO_POWER_MANAGEMENT structures). So we define what prototypes
// we need here:
extern "C" {
typedef enum VIDEO_SYNCHRONIZE_PRIORITY {
VpLowPriority,
VpMediumPriority,
VpHighPriority
} VIDEO_SYNCHRONIZE_PRIORITY, *PVIDEO_SYNCHRONIZE_PRIORITY;
typedef
BOOLEAN
(*PMINIPORT_SYNCHRONIZE_ROUTINE)(
PVOID Context
);
VOID
VideoPortSynchronizeExecution(
PVOID HwDeviceExtension,
VIDEO_SYNCHRONIZE_PRIORITY Priority,
PMINIPORT_SYNCHRONIZE_ROUTINE synchronizeRoutine,
PVOID Context
);
};
VOID
DxEventDpc(
PKDPC pDpc,
PVOID pvContext,
PVOID pvArgument1,
PVOID pvArgument2
)
{
EDD_DXDIRECTDRAW* peDxDirectDraw;
DX_IRQDATA* pIrqData;
DXAPI_EVENT* pDxEvent;
DWORD dwIrqFlags;
DWORD i;
pIrqData = (DX_IRQDATA*) pvArgument1;
peDxDirectDraw = (EDD_DXDIRECTDRAW*) pvContext;
// The ISR can be triggered even while we're processing the DPC for
// its previous interrupt. Consequently, we have to access the
// interrupt flags in a routine that is synchronized to the ISR
// routine.
//
// Note that we don't call KeSynchronizeExecution directly, because
// we don't have the device's interrupt object.
VideoPortSynchronizeExecution(peDxDirectDraw->HwDeviceExtension,
VpMediumPriority,
DxGetIrqFlags,
peDxDirectDraw);
dwIrqFlags = peDxDirectDraw->dwSynchedIrqFlags;
// We must acquire a spinlock while traversing the event list to
// protect against simultaneous modifications to the list.
KeAcquireSpinLockAtDpcLevel(&peDxDirectDraw->SpinLock);
// We call the callbacks registered by the client before we
// call the ones that we registered so we give the client a chance
// to skip fields before we execute our skip logic. This is why
// we keep two dispatch lists.
for (i = 0; i < NUM_DISPATCH_LISTS; i++)
{
for (pDxEvent = peDxDirectDraw->pDxEvent_DispatchList[i];
pDxEvent != NULL;
pDxEvent = pDxEvent->pDxEvent_Next)
{
if (pDxEvent->dwIrqFlag & dwIrqFlags)
{
pDxEvent->pfnCallBack(pDxEvent->dwEvent, pDxEvent->pContext, 0, 0);
}
}
}
// If it was a busmaster IRQ, take care of them as well
if (dwIrqFlags & DDIRQ_BUSMASTER)
{
for (pDxEvent = peDxDirectDraw->pDxEvent_CaptureList;
pDxEvent != NULL;
pDxEvent = pDxEvent->pDxEvent_Next)
{
pDxEvent->pfnCallBack(pDxEvent->dwEvent, pDxEvent->pContext, 0, 0);
}
}
KeReleaseSpinLockFromDpcLevel(&peDxDirectDraw->SpinLock);
}
/******************************Public*Routine******************************\
* VOID vDxFlip
*
* Assumes the spinlock is held.
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
vDxFlip(
EDD_DXVIDEOPORT* peDxVideoPort,
DWORD dwFlags
)
{
EDD_DXDIRECTDRAW* peDxDirectDraw;
DWORD iOldVideo;
DWORD iOldVbi;
DWORD iOldOverlay;
DWORD iNewVideo;
DWORD iNewVbi;
DWORD iNewOverlay;
DDFLIPVIDEOPORTINFO FlipVideoPortInfo;
DDFLIPOVERLAYINFO FlipOverlayInfo;
DWORD dwRet;
DWORD dwTemp;
ASSERTDX(KeGetCurrentIrql() == DISPATCH_LEVEL, "Expected held spinlock");
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
if( dwFlags == DDVPFLIP_VBI )
{
if (peDxVideoPort->cAutoflipVbi != 0)
{
// Flip videoport VBI surface:
iOldVbi = peDxVideoPort->iCurrentVbi;
iNewVbi = iOldVbi + 1;
if (iNewVbi >= peDxVideoPort->cAutoflipVbi)
iNewVbi = 0;
peDxVideoPort->iCurrentVbi = iNewVbi;
FlipVideoPortInfo.lpVideoPortData
= peDxVideoPort;
FlipVideoPortInfo.lpCurrentSurface
= peDxVideoPort->apeDxSurfaceVbi[iOldVbi];
FlipVideoPortInfo.lpTargetSurface
= peDxVideoPort->apeDxSurfaceVbi[iNewVbi];
FlipVideoPortInfo.dwFlipVPFlags = DDVPFLIP_VBI;
if (peDxDirectDraw->DxApiInterface.DxFlipVideoPort)
{
dwRet = peDxDirectDraw->DxApiInterface.DxFlipVideoPort(
peDxDirectDraw->HwDeviceExtension,
&FlipVideoPortInfo,
NULL);
}
}
}
else if( dwFlags == DDVPFLIP_VIDEO )
{
if (peDxVideoPort->cAutoflipVideo != 0)
{
// Flip videoport video surface:
iOldVideo = peDxVideoPort->iCurrentVideo;
iNewVideo = iOldVideo + 1;
if (iNewVideo >= peDxVideoPort->cAutoflipVideo)
iNewVideo = 0;
peDxVideoPort->iCurrentVideo = iNewVideo;
FlipVideoPortInfo.lpVideoPortData
= peDxVideoPort;
FlipVideoPortInfo.lpCurrentSurface
= peDxVideoPort->apeDxSurfaceVideo[iOldVideo];
FlipVideoPortInfo.lpTargetSurface
= peDxVideoPort->apeDxSurfaceVideo[iNewVideo];
FlipVideoPortInfo.dwFlipVPFlags
= DDVPFLIP_VIDEO;
if (peDxDirectDraw->DxApiInterface.DxFlipVideoPort)
{
dwRet = peDxDirectDraw->DxApiInterface.DxFlipVideoPort(
peDxDirectDraw->HwDeviceExtension,
&FlipVideoPortInfo,
NULL);
}
// Flip overlay surface:
if( ( peDxVideoPort->apeDxSurfaceVideo[0] != NULL ) &&
( peDxVideoPort->apeDxSurfaceVideo[0]->ddsCaps & DDSCAPS_OVERLAY ) &&
( ( peDxVideoPort->apeDxSurfaceVideo[0]->dwOverlayFlags & DDOVER_AUTOFLIP ) ||
( peDxVideoPort->bSoftwareAutoflip ) ) )
{
// If there are two surfaces, flip to the opposite surface. If
// there are more than two surfaces, flip to dwNumAutoflip - 2.
dwTemp = 1;
if( peDxVideoPort->cAutoflipVideo != 2 )
{
dwTemp++;
}
dwTemp = peDxVideoPort->iCurrentVideo +
peDxVideoPort->cAutoflipVideo - dwTemp;
if( dwTemp >= peDxVideoPort->cAutoflipVideo )
{
dwTemp -= peDxVideoPort->cAutoflipVideo;
}
FlipOverlayInfo.lpTargetSurface
= peDxVideoPort->apeDxSurfaceVideo[dwTemp];
if( dwTemp == 0 )
{
dwTemp = peDxVideoPort->cAutoflipVideo;
}
FlipOverlayInfo.lpCurrentSurface
= peDxVideoPort->apeDxSurfaceVideo[--dwTemp];
FlipOverlayInfo.dwFlags = 0;
if (peDxDirectDraw->DxApiInterface.DxFlipOverlay)
{
dwRet = peDxDirectDraw->DxApiInterface.DxFlipOverlay(
peDxDirectDraw->HwDeviceExtension,
&FlipOverlayInfo,
NULL);
}
}
}
}
}
/******************************Public*Routine******************************\
* VOID vDxBob
*
* Assumes the spinlock is held.
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
vDxBob(
EDD_DXVIDEOPORT* peDxVideoPort
)
{
EDD_DXDIRECTDRAW* peDxDirectDraw;
DDBOBNEXTFIELDINFO BobNextFieldInfo;
DWORD dwRet;
DWORD dwTemp;
ASSERTDX(KeGetCurrentIrql() == DISPATCH_LEVEL, "Expected held spinlock");
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
// Get the current surface handle. This is tricky because
// dwCurrentBuffer tells us which surface the video port is
// writting to - not which surface has the overlay. Therefore,
// we re-create the algorithm used in DoFlip to get the surface.
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP )
{
dwTemp = 1;
if( peDxVideoPort->cAutoflipVideo != 2 )
{
dwTemp++;
}
dwTemp = peDxVideoPort->iCurrentVideo +
peDxVideoPort->cAutoflipVideo - dwTemp;
if( dwTemp >= peDxVideoPort->cAutoflipVideo )
{
dwTemp -= peDxVideoPort->cAutoflipVideo;
}
}
else
{
dwTemp = 0;
}
BobNextFieldInfo.lpSurface = peDxVideoPort->apeDxSurfaceVideo[dwTemp];
if (peDxDirectDraw->DxApiInterface.DxBobNextField)
{
dwRet = peDxDirectDraw->DxApiInterface.DxBobNextField(
peDxDirectDraw->HwDeviceExtension,
&BobNextFieldInfo,
NULL);
}
}
/******************************Public*Routine******************************\
* VOID vDxSkip
*
* Assumes the spinlock is held.
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
vDxSkip(
EDD_DXVIDEOPORT* peDxVideoPort,
DWORD dwFlags
)
{
EDD_DXDIRECTDRAW* peDxDirectDraw;
DDSKIPNEXTFIELDINFO SkipNextFieldInfo;
DWORD dwRet;
ASSERTDX(KeGetCurrentIrql() == DISPATCH_LEVEL, "Expected held spinlock");
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
if (peDxDirectDraw->DxApiInterface.DxSkipNextField)
{
SkipNextFieldInfo.lpVideoPortData = peDxVideoPort;
SkipNextFieldInfo.dwSkipFlags = dwFlags;
dwRet = peDxDirectDraw->DxApiInterface.DxSkipNextField(
peDxDirectDraw->HwDeviceExtension,
&SkipNextFieldInfo,
NULL);
}
}
/******************************Public*Routine******************************\
* VOID IRQCapture
*
* This routine initiates video/VBI capture based on a video port VSYNC.
*
* NOTE: The spinlock is already held.
*
* 10-Jan-1998 -by- Scott MacDonald [smac]
* Wrote it.
\**************************************************************************/
VOID IRQCapture(
EDD_DXVIDEOPORT* peDxVideoPort,
EDD_DXDIRECTDRAW* peDxDirectDraw
)
{
DDGETCURRENTAUTOFLIPININFO ddAutoflipInInfo;
DDGETCURRENTAUTOFLIPOUTINFO ddAutoflipOutInfo;
EDD_DXCAPTURE* peDxCapture;
LPDDCAPBUFFINFO lpBuffInfo;
DXCAPTUREBUFF* lpBuff;
DDTRANSFERININFO ddTransferIn;
DDTRANSFEROUTINFO ddTransferOut;
ULONGLONG ullTimeStamp;
PULONGLONG pullTemp;
ULONGLONG rate;
DWORD dwVBIIndex;
DWORD dwVideoIndex;
BOOL bStarved = TRUE;
DWORD ddRVal;
// Get the current time stamp
ullTimeStamp = (ULONGLONG)KeQueryPerformanceCounter((PLARGE_INTEGER)&rate).QuadPart;
ullTimeStamp = (ullTimeStamp & 0xFFFFFFFF00000000) / rate * 10000000 +
(ullTimeStamp & 0xFFFFFFFF) * 10000000 / rate;
// If either the VBI or video is being hardware autoflipped, figure out
// the correct buffers.
dwVBIIndex = 0;
dwVideoIndex = 0;
if( ( ( peDxVideoPort->cAutoflipVbi > 1 ) &&
!( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI ) ) ||
( ( peDxVideoPort->cAutoflipVideo > 1 ) &&
!( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP ) ) )
{
ddAutoflipInInfo.lpVideoPortData = peDxVideoPort;
ddAutoflipOutInfo.dwSurfaceIndex = 0;
if (peDxDirectDraw->DxApiInterface.DxGetCurrentAutoflip)
{
ddRVal = peDxDirectDraw->DxApiInterface.DxGetCurrentAutoflip(
peDxDirectDraw->HwDeviceExtension,
&ddAutoflipInInfo,
&ddAutoflipOutInfo);
}
if( peDxVideoPort->cAutoflipVideo > 0 )
{
dwVideoIndex = ddAutoflipOutInfo.dwSurfaceIndex;
if( dwVideoIndex-- == 0 )
{
dwVideoIndex = peDxVideoPort->cAutoflipVideo - 1;
}
}
if( peDxVideoPort->cAutoflipVbi > 0 )
{
dwVBIIndex = ddAutoflipOutInfo.dwVBISurfaceIndex;
if( dwVBIIndex-- == 0 )
{
dwVBIIndex = peDxVideoPort->cAutoflipVbi - 1;
}
}
}
// Which is the surface containing the most recent VBI data?
if( ( peDxVideoPort->cAutoflipVbi > 0 ) &&
( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI ) )
{
dwVBIIndex = peDxVideoPort->iCurrentVbi;
if( dwVBIIndex-- == 0 )
{
dwVBIIndex = peDxVideoPort->cAutoflipVbi - 1;
}
}
// Which is the surface containing the most recent video data?
if( ( peDxVideoPort->cAutoflipVideo > 0 ) &&
( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP ) )
{
dwVideoIndex = peDxVideoPort->iCurrentVideo;
if( dwVideoIndex-- == 0 )
{
dwVideoIndex = peDxVideoPort->cAutoflipVideo - 1;
}
}
// Look at each capture device to determine if it has to do a busmaster
// or not
peDxCapture = peDxVideoPort->peDxCapture;
while( peDxCapture != NULL )
{
if( ( peDxCapture->CaptureQueue[peDxCapture->dwBottom].flFlags & DD_DXCAPTUREBUFF_FLAG_IN_USE ) &&
!( peDxCapture->CaptureQueue[peDxCapture->dwBottom].flFlags & DD_DXCAPTUREBUFF_FLAG_WAITING ) )
{
bStarved = FALSE;
if( peDxCapture->dwCaptureCountDown-- == 1 )
{
peDxCapture->dwCaptureCountDown = peDxCapture->dwCaptureEveryNFields;
lpBuff = &(peDxCapture->CaptureQueue[peDxCapture->dwBottom]);
// Fill in the buffer info
lpBuffInfo = (LPDDCAPBUFFINFO) lpBuff->lpBuffInfo;
lpBuffInfo->dwFieldNumber = peDxVideoPort->dwCurrentField;
pullTemp = (PULONGLONG) &(lpBuffInfo->liTimeStamp);
*pullTemp = ullTimeStamp;
// Tell mini port to do the transfer
ddTransferIn.dwStartLine = peDxCapture->dwStartLine;
ddTransferIn.dwEndLine = peDxCapture->dwEndLine;
ddTransferIn.dwTransferFlags = lpBuff->dwClientFlags;
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_HALFLINES )
{
ddTransferIn.dwTransferFlags |= DDTRANSFER_HALFLINES;
}
ddTransferIn.lpDestMDL = lpBuff->pBuffMDL;
if( peDxCapture->flFlags & DD_DXCAPTURE_FLAG_VIDEO )
{
ddTransferIn.lpSurfaceData = peDxVideoPort->apeDxSurfaceVideo[dwVideoIndex];
}
else
{
ddTransferIn.lpSurfaceData = peDxVideoPort->apeDxSurfaceVbi[dwVBIIndex];
}
if (ddTransferIn.lpSurfaceData)
{
ddTransferIn.dwTransferID = (ULONG_PTR) peDxCapture;
ddTransferIn.dwTransferID &= ~0xf;
ddTransferIn.dwTransferID |= peDxCapture->dwBottom;
ddRVal = DDERR_UNSUPPORTED;
if (peDxDirectDraw->DxApiInterface.DxTransfer)
{
ddRVal = peDxDirectDraw->DxApiInterface.DxTransfer(
peDxDirectDraw->HwDeviceExtension,
&ddTransferIn,
&ddTransferOut);
}
}
else
{
ddRVal = DDERR_INVALIDPARAMS;
}
lpBuffInfo->ddRVal = ddRVal;
if( ddRVal != DD_OK )
{
// Set the KEvent now
KeSetEvent( lpBuff->pBuffKEvent, 0, 0 );
lpBuff->flFlags = 0;
lpBuff->pBuffKEvent = 0;
}
else
{
// Mark the lucky surface as doing a transfer
lpBuffInfo->bPolarity = ddTransferOut.dwBufferPolarity;
lpBuff->peDxSurface = (EDD_DXSURFACE*) ddTransferIn.lpSurfaceData;
lpBuff->peDxSurface->flFlags |= DD_DXSURFACE_FLAG_TRANSFER;
lpBuff->flFlags |= DD_DXCAPTUREBUFF_FLAG_WAITING;
}
// Next time use the next buffer
if( ++( peDxCapture->dwBottom ) >= DXCAPTURE_MAX_CAPTURE_BUFFS )
{
peDxCapture->dwBottom = 0;
}
}
}
peDxCapture = peDxCapture->peDxCaptureNext;
}
if( bStarved )
{
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_CAPTURING;
}
}
/******************************Public*Routine******************************\
* VOID DxAutoflipDpc
*
* This routine handles 'software autoflipping' and is called at dispatch
* level when the miniport's videoport interrupt is triggered. This routine
* can't be kept in 'win32k.sys' because it needs to be non-pageable.
*
* NOTE: The spinlock is already held.
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxAutoflipDpc(
DWORD dwEvent,
PVOID pContext,
DWORD dwParam1,
DWORD dwParam2
)
{
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXVIDEOPORT* peDxVideoPort;
DWORD dwCurrentField;
BOOL bAdjustFirstWeave;
BOOL bSkipped;
BOOL bFlipped;
ASSERTDX(KeGetCurrentIrql() == DISPATCH_LEVEL, "Expected dispath level");
ASSERTDX(dwEvent == DDEVENT_VP_VSYNC, "Expected VP_VSYNC event");
peDxVideoPort = (EDD_DXVIDEOPORT*) pContext;
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
// If capturing, do it now
if( ( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_CAPTURING ) &&
( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_ON ) )
{
IRQCapture(peDxVideoPort, peDxDirectDraw);
}
// Do we need to notify user mode that a vsync occurred?
if ((peDxVideoPort->pNotifyEvent != NULL) &&
(peDxVideoPort->pNotifyBuffer != NULL) &&
(1 == InterlockedExchange( &peDxVideoPort->pNotifyBuffer->lDone, 0 ) ) )
{
DDGETCURRENTAUTOFLIPININFO ddAutoflipInInfo;
DDGETCURRENTAUTOFLIPOUTINFO ddAutoflipOutInfo;
ULONGLONG ullTimeStamp;
ULONGLONG rate;
UINT dwVideoIndex;
// Fill in the buffer
peDxVideoPort->pNotifyBuffer->lField = -1;
if ( peDxDirectDraw->DxApiInterface.DxGetPolarity )
{
DDGETPOLARITYININFO ddPolarityInInfo;
DDGETPOLARITYOUTINFO ddPolarityOutInfo;
ddPolarityInInfo.lpVideoPortData = peDxVideoPort;
peDxDirectDraw->DxApiInterface.DxGetPolarity( peDxDirectDraw->HwDeviceExtension,
&ddPolarityInInfo, &ddPolarityOutInfo );
peDxVideoPort->pNotifyBuffer->lField = ddPolarityOutInfo.bPolarity ? 1 : 0;
}
dwVideoIndex = 0;
if (peDxVideoPort->cAutoflipVideo > 1 )
{
if (peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP)
{
dwVideoIndex = peDxVideoPort->iCurrentVideo;
}
else
{
ddAutoflipInInfo.lpVideoPortData = peDxVideoPort;
ddAutoflipOutInfo.dwSurfaceIndex = 0;
if (peDxDirectDraw->DxApiInterface.DxGetCurrentAutoflip)
{
peDxDirectDraw->DxApiInterface.DxGetCurrentAutoflip(
peDxDirectDraw->HwDeviceExtension,
&ddAutoflipInInfo,
&ddAutoflipOutInfo);
}
dwVideoIndex = ddAutoflipOutInfo.dwSurfaceIndex;
}
if( dwVideoIndex-- == 0 )
{
dwVideoIndex = peDxVideoPort->cAutoflipVideo - 1;
}
}
peDxVideoPort->pNotifyBuffer->dwSurfaceIndex = dwVideoIndex;
ullTimeStamp = (ULONGLONG)KeQueryPerformanceCounter((PLARGE_INTEGER)&rate).QuadPart;
ullTimeStamp = (ullTimeStamp & 0xFFFFFFFF00000000) / rate * 10000000 +
(ullTimeStamp & 0xFFFFFFFF) * 10000000 / rate;
*((ULONGLONG*)&(peDxVideoPort->pNotifyBuffer->ApproximateTimeStamp)) = ullTimeStamp;
KeSetEvent (peDxVideoPort->pNotifyEvent, IO_NO_INCREMENT, FALSE);
}
// Note that it is okay to modify 'dwCurrentField' outside of a spinlock,
// as the only other routine that modifies it is 'DxSetFieldNumber' and
// it always does an atomic write.
dwCurrentField = InterlockedIncrement((LONG*) &peDxVideoPort->dwCurrentField);
// Check for posted state changes
bAdjustFirstWeave = FALSE;
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_NEW_STATE )
{
if( peDxVideoPort->dwSetStateField-- == 0 )
{
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_NEW_STATE;
// If we'll be weaving, we need to make sure that
// we only flip at the beginning of a frame and not
// during the middle. We assume that we're told to
// star weaving at the beginning of the frame.
if( ( peDxVideoPort->dwSetStateState & DDSTATE_WEAVE ) &&
!( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_FLIP_NEXT ) )
{
bAdjustFirstWeave = TRUE;
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_FLIP_NEXT;
}
EffectStateChange( peDxVideoPort, NULL, peDxVideoPort->dwSetStateState );
}
}
// Check the skip logic
bSkipped = FALSE;
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_SKIP_SET )
{
if( peDxVideoPort->dwFieldToSkip-- == 0 )
{
// Tell the MiniPort to skip the next field
vDxSkip( peDxVideoPort, DDSKIP_SKIPNEXT );
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_SKIPPED_LAST;
bSkipped = TRUE;
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_NEXT_SKIP_SET )
{
peDxVideoPort->dwFieldToSkip = peDxVideoPort->dwNextFieldToSkip;
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_NEXT_SKIP_SET;
}
else
{
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_SKIP_SET;
}
}
else if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_NEXT_SKIP_SET )
{
peDxVideoPort->dwNextFieldToSkip--;
}
}
if( ( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_SKIPPED_LAST ) && !bSkipped )
{
// Tell the MiniPort to un-skip the next field
vDxSkip( peDxVideoPort, DDSKIP_ENABLENEXT );
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_SKIPPED_LAST;
// This next part is a hack.We keep track of which fields
// to flip on in weave mode during the ISR, but what if we
// happen to miss an IRQ (due to DOS box, etc.)? We can't
// use to polarity to re-sync because field skipping screws
// that up, so this code assume that the repeat field will
// always be the last field of a frame and so the following
// field will be the first field. This will make it re-sync
// if we ever miss an IRQ.
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_FLIP_NEXT;
}
// Now do all of the autoflipping
if( peDxVideoPort->flFlags & (DD_DXVIDEOPORT_FLAG_AUTOFLIP|
DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI|DD_DXVIDEOPORT_FLAG_BOB ) )
{
// Check for autoflipping the VBI surface in which case we
// don't care about the skip logic
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI )
{
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_VBI_INTERLEAVED )
{
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_FLIP_NEXT_VBI )
{
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_FLIP_NEXT_VBI;
vDxFlip( peDxVideoPort, DDVPFLIP_VBI );
}
else
{
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_FLIP_NEXT_VBI;
}
}
else
{
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_FLIP_NEXT_VBI;
vDxFlip( peDxVideoPort, DDVPFLIP_VBI );
}
}
// Autoflip the vhe video if we are not skipping this field
if( !bSkipped )
{
bFlipped = FALSE;
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_AUTOFLIP )
{
if( peDxVideoPort->dwVPFlags & DDVP_INTERLEAVE )
{
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_FLIP_NEXT )
{
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_FLIP_NEXT;
if( !bAdjustFirstWeave )
{
vDxFlip( peDxVideoPort, DDVPFLIP_VIDEO );
bFlipped = TRUE;
}
}
else
{
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_FLIP_NEXT;
}
}
else
{
vDxFlip( peDxVideoPort, DDVPFLIP_VIDEO );
bFlipped = TRUE;
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_FLIP_NEXT;
}
}
// They may be bobbing even when not autoflipping
// (they may have one interleaved buffer that they
// use for bob - technically this is not a flip since
// only one surface is involved).
if( ( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_BOB ) &&
!bFlipped )
{
vDxBob( peDxVideoPort );
}
}
}
}
/******************************Public*Routine******************************\
* VOID DxBusmasterDpc
*
* This routine handles the video capture and is called when one of
* the buffers is filled. It figures out which one and then sets the
* compeletion event for that buffer.
*
* NOTE: The spinlock is already held.
*
* 10-Jan-1998 -by- Scott MacDonald [smac]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxBusmasterDpc(
DWORD dwEvent,
PVOID pContext,
DWORD dwParam1,
DWORD dwParam2
)
{
DDGETTRANSFERSTATUSOUTINFO ddGetTransferStatus;
EDD_DXVIDEOPORT* peDxVideoPort;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXCAPTURE* peDxCapture;
DWORD ddRVal;
ULONG_PTR dwTempId;
DWORD dwTempIndex;
// Call the miniport to get the transfer ID of the completed busmaster
ddRVal = DDERR_UNSUPPORTED;
peDxVideoPort = (EDD_DXVIDEOPORT*) pContext;
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
if (peDxDirectDraw->DxApiInterface.DxGetTransferStatus)
{
ddRVal = peDxDirectDraw->DxApiInterface.DxGetTransferStatus(
peDxDirectDraw->HwDeviceExtension,
NULL,
&ddGetTransferStatus);
}
if( ddRVal == DD_OK )
{
// Find the capture object. It may not even be associated with this
// video port if multiple vidoe ports exist in the system.
dwTempId = ddGetTransferStatus.dwTransferID & ~0xf;
peDxCapture = peDxVideoPort->peDxCapture;
while (peDxCapture && (((ULONG_PTR)peDxCapture & ~0xf) != dwTempId))
{
peDxCapture = peDxCapture->peDxCaptureNext;
}
if (peDxCapture != NULL)
{
// We've found the capture object
dwTempIndex = (DWORD)(ddGetTransferStatus.dwTransferID & 0xf);
if (peDxCapture->CaptureQueue[dwTempIndex].flFlags & DD_DXCAPTUREBUFF_FLAG_WAITING )
{
peDxCapture->CaptureQueue[dwTempIndex].flFlags = 0;
KeSetEvent(peDxCapture->CaptureQueue[dwTempIndex].pBuffKEvent, 0, 0);
}
// Mark the lucky surface as being done w/ the transfer
peDxCapture->CaptureQueue[dwTempIndex].peDxSurface->flFlags
&= ~DD_DXSURFACE_FLAG_TRANSFER;
peDxCapture->CaptureQueue[dwTempIndex].peDxSurface = NULL;
}
}
}
/******************************Public*Routine******************************\
* VOID DxAutoflipUpdate
*
* This routine handles 'software autoflipping' and is called at dispatch
* level when the miniport's videoport interrupt is triggered. This routine
* can't be kept in 'win32k.sys' because it needs to be non-pageable.
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxAutoflipUpdate(
EDD_DXVIDEOPORT* peDxVideoPort,
EDD_DXSURFACE** apeDxSurfaceVideo,
ULONG cSurfacesVideo,
EDD_DXSURFACE** apeDxSurfaceVbi,
ULONG cSurfacesVbi
)
{
KIRQL OldIrql;
ULONG i;
KeAcquireSpinLock(&peDxVideoPort->peDxDirectDraw->SpinLock, &OldIrql);
peDxVideoPort->cAutoflipVideo = cSurfacesVideo;
for (i = 0; i < cSurfacesVideo; i++)
{
peDxVideoPort->apeDxSurfaceVideo[i] = apeDxSurfaceVideo[i];
peDxVideoPort->apeDxSurfaceVideo[i]->peDxVideoPort = peDxVideoPort;
}
peDxVideoPort->cAutoflipVbi = cSurfacesVbi;
for (i = 0; i < cSurfacesVbi; i++)
{
peDxVideoPort->apeDxSurfaceVbi[i] = apeDxSurfaceVbi[i];
peDxVideoPort->apeDxSurfaceVbi[i]->peDxVideoPort = peDxVideoPort;
}
KeReleaseSpinLock(&peDxVideoPort->peDxDirectDraw->SpinLock, OldIrql);
}
/******************************Public*Routine******************************\
* VOID DxLoseObject
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxLoseObject(
VOID* pvObject,
LOTYPE loType
)
{
KIRQL OldIrql;
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DXVIDEOPORT* peDxVideoPort;
EDD_DXSURFACE* peDxSurface;
EDD_DXCAPTURE* peDxCapture;
DXAPI_EVENT* pDxEvent;
DDENABLEIRQINFO EnableIrqInfo;
DWORD dwRet;
switch (loType)
{
case LO_DIRECTDRAW:
peDxDirectDraw = (EDD_DXDIRECTDRAW*) pvObject;
peDxDirectDraw->peDirectDrawGlobal->peDxDirectDraw = NULL; // Passive
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
peDxDirectDraw->bLost = TRUE;
peDxDirectDraw->peDirectDrawGlobal = NULL;
if (peDxDirectDraw->DxApiInterface.DxEnableIrq)
{
// Make sure all IRQs are disabled
EnableIrqInfo.dwIRQSources = 0;
EnableIrqInfo.dwLine = 0;
EnableIrqInfo.IRQCallback = NULL;
EnableIrqInfo.lpIRQData = NULL;
peDxDirectDraw->DxApiInterface.DxEnableIrq(
peDxDirectDraw->HwDeviceExtension,
&EnableIrqInfo,
NULL);
}
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
break;
case LO_VIDEOPORT:
peDxVideoPort = (EDD_DXVIDEOPORT*) pvObject;
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
peDxVideoPort->peVideoPort->peDxVideoPort = NULL; // Passive
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
peDxVideoPort->bLost = TRUE;
peDxVideoPort->peVideoPort = NULL;
peDxVideoPort->peDxCapture = NULL;
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
break;
case LO_SURFACE:
peDxSurface = (EDD_DXSURFACE*) pvObject;
peDxDirectDraw = peDxSurface->peDxDirectDraw;
peDxSurface->peSurface->peDxSurface = NULL; // Passive
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
peDxSurface->bLost = TRUE;
peDxSurface->peSurface = NULL;
peDxSurface->peDxVideoPort = NULL;
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
break;
case LO_CAPTURE:
peDxCapture = (EDD_DXCAPTURE*) pvObject;
peDxVideoPort = peDxCapture->peDxVideoPort;
if( peDxVideoPort != NULL )
{
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
KeAcquireSpinLock(&peDxDirectDraw->SpinLock, &OldIrql);
// First flush the capture buffers
DxInternalFlushVpCaptureBuffs( peDxDirectDraw, peDxVideoPort, peDxCapture );
// Disassociate the capture object from the video port
peDxCapture->peDxVideoPort = NULL;
peDxCapture->bLost = TRUE;
if( peDxVideoPort->peDxCapture == peDxCapture )
{
peDxVideoPort->peDxCapture = peDxCapture->peDxCaptureNext;
}
else
{
EDD_DXCAPTURE* peDxTemp;
for( peDxTemp = peDxVideoPort->peDxCapture;
( peDxTemp != NULL ) &&
( peDxTemp->peDxCaptureNext != peDxCapture );
peDxTemp = peDxTemp->peDxCaptureNext );
if( peDxTemp != NULL )
{
peDxTemp->peDxCaptureNext = peDxCapture->peDxCaptureNext;
}
else
{
RIPDX("Capture object not in video port list");
}
}
// If there are no more capture objects associated with the
// video port, remove the video port from the capture list.
pDxEvent = NULL;
if( peDxVideoPort->peDxCapture == NULL )
{
if( peDxDirectDraw->pDxEvent_CaptureList->peDxVideoPort == peDxVideoPort )
{
pDxEvent = peDxDirectDraw->pDxEvent_CaptureList;
peDxDirectDraw->pDxEvent_CaptureList = pDxEvent->pDxEvent_Next;
}
else
{
for( pDxEvent = peDxDirectDraw->pDxEvent_CaptureList;
(pDxEvent != NULL) &&
(pDxEvent->pDxEvent_Next->peDxVideoPort != peDxVideoPort);
pDxEvent = pDxEvent->pDxEvent_Next );
if( pDxEvent != NULL )
{
pDxEvent->pDxEvent_Next =
pDxEvent->pDxEvent_Next->pDxEvent_Next;
pDxEvent = pDxEvent->pDxEvent_Next;
}
}
}
KeReleaseSpinLock(&peDxDirectDraw->SpinLock, OldIrql);
if( pDxEvent != NULL )
{
ExFreePool(pDxEvent);
}
}
break;
default:
RIPDX("Unexpected type");
}
}
/******************************Public*Routine******************************\
* VOID DxUpdateCapture
*
* This routine inserts capture devices intot he list handling off of the
* video port. Since this list is walked at DPC level, we need to
* synchronize this with the DPC.
*
* 10-Jan-1997 -by- Scott MacDonald [smac]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxUpdateCapture(
EDD_DXVIDEOPORT* peDxVideoPort,
EDD_DXCAPTURE* peDxCapture,
BOOL bRemove
)
{
KIRQL OldIrql;
EDD_DXCAPTURE* peDxTemp;
EDD_DXDIRECTDRAW* peDxDirectDraw;
DXAPI_EVENT* pDxEvent_New;
DXAPI_EVENT* pDxEvent_Temp = NULL;
DWORD dwRet;
// If adding to the list, also an event to the capture list so we
// can get the busmaster complete notification. Allocate the
// memory for this now.
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
if( !bRemove )
{
pDxEvent_New = (DXAPI_EVENT*) ExAllocatePoolWithTag(NonPagedPool,
sizeof(*pDxEvent_New),
'eddG');
if (pDxEvent_New == NULL)
return;
RtlZeroMemory(pDxEvent_New, sizeof(*pDxEvent_New));
pDxEvent_New->peDxDirectDraw = peDxDirectDraw;
pDxEvent_New->peDxVideoPort = peDxVideoPort;
pDxEvent_New->pfnCallBack = (LPDD_NOTIFYCALLBACK) DxBusmasterDpc;
pDxEvent_New->pContext = peDxVideoPort;
}
KeAcquireSpinLock(&peDxVideoPort->peDxDirectDraw->SpinLock, &OldIrql);
if( bRemove )
{
// First flush the capture buffers
DxInternalFlushVpCaptureBuffs( peDxDirectDraw, peDxVideoPort, peDxCapture );
// Disassociate the capture object with the video port
if( peDxVideoPort->peDxCapture == peDxCapture )
{
peDxVideoPort->peDxCapture = peDxCapture->peDxCaptureNext;
}
else
{
for( peDxTemp = peDxVideoPort->peDxCapture;
( peDxTemp != NULL ) &&
( peDxTemp->peDxCaptureNext != peDxCapture );
peDxTemp = peDxTemp->peDxCaptureNext );
if( peDxTemp != NULL )
{
peDxTemp->peDxCaptureNext = peDxCapture->peDxCaptureNext;
}
}
peDxCapture->peDxVideoPort = NULL;
// If there are no more capture objects associated with the
// video port, remove the video port from the capture list.
if( peDxVideoPort->peDxCapture == NULL )
{
pDxEvent_Temp = NULL;
if( peDxDirectDraw->pDxEvent_CaptureList->peDxVideoPort == peDxVideoPort )
{
pDxEvent_Temp = peDxDirectDraw->pDxEvent_CaptureList;
peDxDirectDraw->pDxEvent_CaptureList = pDxEvent_Temp->pDxEvent_Next;
}
else
{
for( pDxEvent_Temp = peDxDirectDraw->pDxEvent_CaptureList;
(pDxEvent_Temp != NULL) &&
(pDxEvent_Temp->pDxEvent_Next->peDxVideoPort != NULL);
pDxEvent_Temp = pDxEvent_Temp->pDxEvent_Next );
if( pDxEvent_Temp != NULL )
{
pDxEvent_Temp->pDxEvent_Next =
pDxEvent_Temp->pDxEvent_Next->pDxEvent_Next;
pDxEvent_Temp = pDxEvent_Temp->pDxEvent_Next;
}
}
}
}
else
{
// Associate the capture object with the video port
peDxCapture->peDxCaptureNext = peDxVideoPort->peDxCapture;
peDxVideoPort->peDxCapture = peDxCapture;
// Add an event to the capture list so we can get the busmaster
// complete notification. First check to see if it's already in
// in the list.
for (pDxEvent_Temp = peDxDirectDraw->pDxEvent_CaptureList;
pDxEvent_Temp != NULL;
pDxEvent_Temp = pDxEvent_Temp->pDxEvent_Next)
{
if (pDxEvent_Temp->peDxVideoPort == peDxVideoPort)
{
break;
}
}
if( pDxEvent_Temp == NULL )
{
// Not already in list - add it
pDxEvent_New->pDxEvent_Next = peDxDirectDraw->pDxEvent_CaptureList;
peDxDirectDraw->pDxEvent_CaptureList = pDxEvent_New;
}
}
KeReleaseSpinLock(&peDxVideoPort->peDxDirectDraw->SpinLock, OldIrql);
if( bRemove && ( pDxEvent_Temp != NULL ) )
{
ExFreePool(pDxEvent_Temp);
}
else if( pDxEvent_Temp != NULL )
{
ExFreePool(pDxEvent_New);
}
}
/******************************Public*Routine******************************\
* DWORD DxOpenDirectDraw
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxOpenDirectDraw(
DDOPENDIRECTDRAWIN* pOpenDirectDrawIn,
DDOPENDIRECTDRAWOUT* pOpenDirectDrawOut
)
{
pOpenDirectDrawOut->ddRVal = DDERR_UNSUPPORTED;
if (pOpenDirectDrawIn != NULL)
{
if (gpfnOpenDirectDraw != NULL)
{
gpfnOpenDirectDraw(pOpenDirectDrawIn,
pOpenDirectDrawOut,
DxEventDpc,
DXAPI_PRIVATE_VERSION_NUMBER);
}
}
}
/******************************Public*Routine******************************\
* VOID DxEnableIRQ
*
* This routine enables/disables the video port VSYNC IRQ and is
* is called at dispatch level.
*
* 17-Oct-1997 -by- smac
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxEnableIRQ(
EDD_DXVIDEOPORT* peDxVideoPort,
BOOL bEnable
)
{
EDD_DXDIRECTDRAW* peDxDirectDraw;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
DWORD dwBit;
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
peDirectDrawGlobal = peDxDirectDraw->peDirectDrawGlobal;
dwBit = DDIRQ_VPORT0_VSYNC << ( peDxVideoPort->dwVideoPortID * 2);
/*
* Don't enable or disable of the IRQ isn't supported
*/
if( ( peDirectDrawGlobal != NULL ) &&
( peDirectDrawGlobal->DDKernelCaps.dwIRQCaps & dwBit ) )
{
if( bEnable )
{
if( !( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_REGISTERED_IRQ ) )
{
bDxModifyDispatchEventList(peDxDirectDraw,
peDxVideoPort,
bEnable,
DDEVENT_VP_VSYNC,
dwBit,
(LPDD_NOTIFYCALLBACK) DxAutoflipDpc,
(PVOID)peDxVideoPort,
INTERNAL_DISPATCH_LIST);
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_REGISTERED_IRQ;
}
}
else
{
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_REGISTERED_IRQ )
{
bDxModifyDispatchEventList(peDxDirectDraw,
peDxVideoPort,
bEnable,
DDEVENT_VP_VSYNC,
dwBit,
(LPDD_NOTIFYCALLBACK) DxAutoflipDpc,
(PVOID)peDxVideoPort,
INTERNAL_DISPATCH_LIST);
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_REGISTERED_IRQ;
}
}
vDxEnableInterrupts( peDxDirectDraw, 0 );
}
}
/******************************Public*Routine******************************\
* DxApi
*
* Single entry point for all DXAPI.SYS public functionality.
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
typedef VOID (APIENTRY* PDX_FUNCTION)(VOID*, VOID*);
typedef struct _DXAPI_ENTRY_POINT {
PDX_FUNCTION pfn;
DWORD cInBuffer;
DWORD cOutBuffer;
BOOLEAN bMapProcess;
} DXAPI_ENTRY_POINT;
#define DX(fn, structin, structout, boolean) \
(PDX_FUNCTION) fn, structin, sizeof(structout), boolean
DXAPI_ENTRY_POINT gDxApiEntryPoint[] = {
DX(DxGetVersionNumber, 0, DDGETVERSIONNUMBER, FALSE ), // 0
DX(NULL, sizeof(DDCLOSEHANDLE), DWORD, TRUE ), // 1
DX(DxOpenDirectDraw, sizeof(DDOPENDIRECTDRAWIN), DDOPENDIRECTDRAWOUT, FALSE ), // 2
DX(NULL, sizeof(DDOPENSURFACEIN), DDOPENSURFACEOUT, TRUE ), // 3
DX(NULL, sizeof(DDOPENVIDEOPORTIN), DDOPENVIDEOPORTOUT, TRUE ), // 4
DX(NULL, sizeof(DWORD), DDGETKERNELCAPSOUT, TRUE ), // 5
DX(DxGetFieldNumber, sizeof(DDGETFIELDNUMIN), DDGETFIELDNUMOUT, FALSE ), // 6
DX(DxSetFieldNumber, sizeof(DDSETFIELDNUM), DWORD, FALSE ), // 7
DX(DxSetSkipPattern, sizeof(DDSETSKIPFIELD), DWORD, FALSE ), // 8
DX(DxGetSurfaceState, sizeof(DDGETSURFACESTATEIN), DDGETSURFACESTATEOUT, FALSE ), // 9
DX(DxSetSurfaceState, sizeof(DDSETSURFACESTATE), DWORD, FALSE ), // 10
DX(DxLock, sizeof(DDLOCKIN), DDLOCKOUT, FALSE ), // 11
DX(DxFlipOverlay, sizeof(DDFLIPOVERLAY), DWORD, FALSE ), // 12
DX(DxFlipVideoPort, sizeof(DDFLIPVIDEOPORT), DWORD, FALSE ), // 13
DX(DxGetCurrentAutoflip, sizeof(DDGETAUTOFLIPIN), DDGETAUTOFLIPOUT, FALSE ), // 14
DX(DxGetPreviousAutoflip, sizeof(DDGETAUTOFLIPIN), DDGETAUTOFLIPOUT, FALSE ), // 15
DX(DxRegisterEvent, sizeof(DDREGISTERCALLBACK), DWORD, FALSE ), // 16
DX(DxUnregisterEvent, sizeof(DDREGISTERCALLBACK), DWORD, FALSE ), // 17
DX(DxGetPolarity, sizeof(DDGETPOLARITYIN), DDGETPOLARITYOUT, FALSE ), // 18
DX(NULL, sizeof(DDOPENVPCAPTUREDEVICEIN),DDOPENVPCAPTUREDEVICEOUT, TRUE ), // 19
DX(DxAddVpCaptureBuffer, sizeof(DDADDVPCAPTUREBUFF), DWORD, FALSE ), // 20
DX(DxFlushVpCaptureBuffs, sizeof(DWORD), DWORD, FALSE ), // 21
};
DWORD
APIENTRY
DxApi(
DWORD iFunction,
VOID* pInBuffer,
DWORD cInBuffer,
VOID* pOutBuffer,
DWORD cOutBuffer
)
{
DWORD dwRet;
BOOL bProcessAttached = FALSE;
dwRet = 0;
iFunction -= DD_FIRST_DXAPI;
if ((iFunction >= sizeof(gDxApiEntryPoint) / sizeof(DXAPI_ENTRY_POINT)) ||
(gDxApiEntryPoint[iFunction].pfn == NULL))
{
KdPrint(("DxApi: Invalid function\n"));
}
else if ((cInBuffer < gDxApiEntryPoint[iFunction].cInBuffer) ||
(cOutBuffer < gDxApiEntryPoint[iFunction].cOutBuffer))
{
KdPrint(("DxApi: Input or output buffer too small\n"));
}
else if (pOutBuffer == NULL)
{
KdPrint(("DxApi: Invalid output buffer specified\n"));
}
else
{
if (gDxApiEntryPoint[iFunction].bMapProcess)
{
PEPROCESS pepSession;
switch (iFunction)
{
case (DD_DXAPI_CLOSEHANDLE - DD_FIRST_DXAPI):
case (DD_DXAPI_OPENSURFACE - DD_FIRST_DXAPI):
case (DD_DXAPI_OPENVIDEOPORT - DD_FIRST_DXAPI):
case (DD_DXAPI_OPENVPCAPTUREDEVICE - DD_FIRST_DXAPI):
// pInBuffer is a pointer to a structure that has
// a pointer to DXOBJ as its first element.
pepSession = ((DXOBJ *)(*(HANDLE *)pInBuffer))->pepSession;
break;
case (DD_DXAPI_GETKERNELCAPS - DD_FIRST_DXAPI):
// pInBuffer is a pointer to DXOBJ.
pepSession = ((DXOBJ *)pInBuffer)->pepSession;
break;
default:
return (dwRet);
}
if (!KeIsAttachedProcess())
{
KeAttachProcess(PsGetProcessPcb(pepSession));
bProcessAttached = TRUE;
}
}
// The return value is the size of the output buffer:
dwRet = gDxApiEntryPoint[iFunction].cOutBuffer;
// Call the actual routine:
gDxApiEntryPoint[iFunction].pfn(pInBuffer, pOutBuffer);
if (bProcessAttached)
{
KeDetachProcess();
}
}
return(dwRet);
}
/******************************Public*Routine******************************\
* VOID DxApiInitialize
*
* Called by win32k.sys to initialize dxapi.sys state.
*
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
APIENTRY
DxApiInitialize(
PFNDXAPIOPENDIRECTDRAW pfnOpenDirectDraw,
PFNDXAPIOPENVIDEOPORT pfnOpenVideoPort,
PFNDXAPIOPENSURFACE pfnOpenSurface,
PFNDXAPICLOSEHANDLE pfnCloseHandle,
PFNDXAPIGETKERNELCAPS pfnGetKernelCaps,
PFNDXAPIOPENCAPTUREDEVICE pfnOpenCaptureDevice,
PFNDXAPILOCKDEVICE pfnLockDevice,
PFNDXAPIUNLOCKDEVICE pfnUnlockDevice
)
{
gpfnOpenDirectDraw = pfnOpenDirectDraw;
gpfnLockDevice = pfnLockDevice;
gpfnUnlockDevice = pfnUnlockDevice;
gDxApiEntryPoint[DD_DXAPI_OPENVIDEOPORT - DD_FIRST_DXAPI].pfn
= (PDX_FUNCTION) pfnOpenVideoPort;
gDxApiEntryPoint[DD_DXAPI_OPENSURFACE - DD_FIRST_DXAPI].pfn
= (PDX_FUNCTION) pfnOpenSurface;
gDxApiEntryPoint[DD_DXAPI_CLOSEHANDLE - DD_FIRST_DXAPI].pfn
= (PDX_FUNCTION) pfnCloseHandle;
gDxApiEntryPoint[DD_DXAPI_GETKERNELCAPS - DD_FIRST_DXAPI].pfn
= (PDX_FUNCTION) pfnGetKernelCaps;
gDxApiEntryPoint[DD_DXAPI_OPENVPCAPTUREDEVICE - DD_FIRST_DXAPI].pfn
= (PDX_FUNCTION) pfnOpenCaptureDevice;
}
/******************************Public*Routine******************************\
* ULONG DxApiGetVersion
*
* The original Memphis DXAPI had this entry point and although it doesn't
* do anything usefull, some drivers called it so we have to support it
* for those drivers to load. It does not return a real version number
* because the original incorrectly returned the DSOUND version 4.02,
* which has no correlation to the DxApi version number. If we return the
* real version, however, we risk breaking drivers.
*
* 16-Apr-1998 -by- Scott MacDonald [smac]
* Wrote it.
\**************************************************************************/
ULONG
APIENTRY
DxApiGetVersion(
VOID
)
{
return( 0x402 );
}