You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4061 lines
135 KiB
4061 lines
135 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: dvpe.cxx
|
|
*
|
|
* Contains all of GDI's private VideoPort APIs.
|
|
*
|
|
* Note that for videoport support, WIN32K.SYS and DXAPI.SYS are closely
|
|
* linked. DXAPI.SYS provides two services:
|
|
*
|
|
* 1. It handles the "software autoflipping" support for the videoports,
|
|
* where the CPU handles the videoport field-done interrupt to
|
|
* flip the overlay and do "bob" and "weave" for better video
|
|
* quality.
|
|
* 2. It provides the public DirectDraw entry points that are callable
|
|
* by other kernel-mode WDM drivers (there is a corresponding DXAPI.SYS
|
|
* module on Memphis/Win95 that exposes the same interface).
|
|
*
|
|
* All of the non-paged code for videoports has to go into DXAPI.SYS since
|
|
* WIN32K.SYS is marked entirely as pageable. WIN32K.SYS handles some
|
|
* functionality on behalf of DXAPI.SYS, such as object opens and closes,
|
|
* since only WIN32K.SYS can access GDI's handle table.
|
|
*
|
|
* Created: 17-Oct-1996
|
|
* Author: Lingyun Wang [LingyunW]
|
|
*
|
|
* Copyright (c) 1996-1999 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
extern PEPROCESS gpepSession;
|
|
|
|
VOID
|
|
vDdDxApiFreeDirectDraw(
|
|
DXOBJ* pDxObj,
|
|
BOOL bDoCallBack
|
|
);
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// DXAPI concerns:
|
|
//
|
|
// - Document that call-back may not occur in context of same process
|
|
// - Refuse to open surface, videoport objects while full-screen
|
|
// Keep DirectDraw open so that POSTFULLSCREEN and DOSBOX can be honored
|
|
// - See InitKernelInterface for init restrictions
|
|
// - Flush DMA buffer before mode changes?
|
|
// - Invalidate dxapi data after mode change?
|
|
// - Right now, DirectDraw DXAPI objects have to be closed last
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// VPE concerns:
|
|
//
|
|
// - Make sure VideoPort's not duplicated on same device
|
|
// - Document that display driver cannot use pool-allocated memory for
|
|
// dwReserved fields on Synchronize calls
|
|
// - Close DxVideoPort objects on full-screen switch?
|
|
// No, to support hardware that can DMA even while full-screen!
|
|
// Okay, but what about mode changes? There's no way they'll not
|
|
// be able to drop frames
|
|
// - Never close DxDirectDraw objects?
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* ULONG vDdNullCallBack
|
|
*
|
|
* The DXAPI register routines require a close call-back routine to notify
|
|
* the client that the object is going away. Since we're really DirectDraw,
|
|
* we already know when the object is going away; hence, this routine doesn't
|
|
* need to do anything.
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ULONG
|
|
vDdNullCallBack(
|
|
DWORD dwFlags,
|
|
PVOID pContext,
|
|
DWORD dwParam1,
|
|
DWORD dwParam2
|
|
)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* VOID vDdUnloadDxApiImage
|
|
*
|
|
* This routine performs the actual unload of DXAPI.SYS.
|
|
*
|
|
* 28-Oct-1997 -by- smac
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdUnloadDxApiImage(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
|
|
)
|
|
{
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_VIDEOPORT* peVideoPortNext;
|
|
EDD_SURFACE* peSurface;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
// Notify clients that the resources are lost and clean up
|
|
|
|
for (peDirectDrawLocal = peDirectDrawGlobal->peDirectDrawLocalList;
|
|
peDirectDrawLocal != NULL;
|
|
peDirectDrawLocal = peDirectDrawLocal->peDirectDrawLocalNext)
|
|
{
|
|
// If any video port still exist (which should not be the case)
|
|
// delete all of the video port objects since the video port assumes
|
|
// that DXAPI.SYS is loaded.
|
|
|
|
for (peVideoPort = peDirectDrawLocal->peVideoPort_DdList;
|
|
peVideoPort != NULL;
|
|
peVideoPort = peVideoPortNext)
|
|
{
|
|
// Don't reference peVideoPort after it's been deleted!
|
|
|
|
peVideoPortNext = peVideoPort->peVideoPort_DdNext;
|
|
bDdDeleteVideoPortObject(peVideoPort->hGet(), NULL);
|
|
}
|
|
|
|
// If a surface still has a client using it, shut it down.
|
|
|
|
peSurface = peDirectDrawLocal->peSurface_Enum(NULL);
|
|
|
|
while (peSurface)
|
|
{
|
|
if (peSurface->hSurface != NULL)
|
|
{
|
|
vDdDxApiFreeSurface( (DXOBJ*) peSurface->hSurface, FALSE );
|
|
peSurface->hSurface = NULL;
|
|
}
|
|
if( peSurface->peDxSurface != NULL )
|
|
{
|
|
vDdLoseDxObjects( peDirectDrawGlobal,
|
|
peSurface->peDxSurface->pDxObj_List,
|
|
(PVOID) peSurface->peDxSurface,
|
|
LO_SURFACE );
|
|
}
|
|
peSurface = peDirectDrawLocal->peSurface_Enum(peSurface);
|
|
}
|
|
}
|
|
if (peDirectDrawGlobal->hDirectDraw != NULL)
|
|
{
|
|
vDdDxApiFreeDirectDraw( (DXOBJ*) peDirectDrawGlobal->hDirectDraw, FALSE );
|
|
}
|
|
if( peDirectDrawGlobal->peDxDirectDraw != NULL )
|
|
{
|
|
vDdLoseDxObjects( peDirectDrawGlobal,
|
|
peDirectDrawGlobal->peDxDirectDraw->pDxObj_List,
|
|
(PVOID) peDirectDrawGlobal->peDxDirectDraw,
|
|
LO_DIRECTDRAW );
|
|
}
|
|
|
|
EngUnloadImage(peDirectDrawGlobal->hDxApi);
|
|
|
|
//
|
|
// Free the memory associate with the module
|
|
//
|
|
|
|
peDirectDrawGlobal->hDxApi = NULL;
|
|
peDirectDrawGlobal->dwDxApiRefCnt = 0;
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* BOOL bDdLoadDxApi
|
|
*
|
|
* This routine loads up DXAPI.SYS and allocates the non-paged DXAPI
|
|
* structures.
|
|
*
|
|
* Returns: FALSE only if a DXAPI resource could not be allocated.
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
* 16-Oct-1977 -by- smac
|
|
* Broke it out into a separate function.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdLoadDxApi(
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal
|
|
)
|
|
{
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
HANDLE hDxApi;
|
|
PFNDXAPIINITIALIZE pfnDxApiInitialize;
|
|
DDOPENDIRECTDRAWIN OpenDirectDrawIn;
|
|
DDOPENDIRECTDRAWOUT OpenDirectDrawOut;
|
|
DWORD dwRet;
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawLocal->peDirectDrawGlobal);
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
/*
|
|
* Don't load if it's already loaded
|
|
*/
|
|
if (peDirectDrawGlobal->hDxApi == NULL)
|
|
{
|
|
ASSERTGDI((peDirectDrawGlobal->hDirectDraw == NULL) &&
|
|
(peDirectDrawGlobal->hDxApi == NULL),
|
|
"Expected NULL hDirectDraw and hDxApi");
|
|
|
|
BOOL loaded;
|
|
|
|
hDxApi = DxEngLoadImage(L"drivers\\dxapi.sys",FALSE);
|
|
if (hDxApi)
|
|
{
|
|
peDirectDrawGlobal->hDxApi = hDxApi;
|
|
peDirectDrawGlobal->pfnDxApi = (LPDXAPI)
|
|
EngFindImageProcAddress(hDxApi, "_DxApi");
|
|
peDirectDrawGlobal->pfnAutoflipUpdate = (PFNAUTOFLIPUPDATE)
|
|
EngFindImageProcAddress(hDxApi, "_DxAutoflipUpdate");
|
|
peDirectDrawGlobal->pfnLoseObject = (PFNLOSEOBJECT)
|
|
EngFindImageProcAddress(hDxApi, "_DxLoseObject");
|
|
pfnDxApiInitialize = (PFNDXAPIINITIALIZE)
|
|
EngFindImageProcAddress(hDxApi, "_DxApiInitialize");
|
|
peDirectDrawGlobal->pfnEnableIRQ = (PFNENABLEIRQ)
|
|
EngFindImageProcAddress(hDxApi, "_DxEnableIRQ");
|
|
peDirectDrawGlobal->pfnUpdateCapture = (PFNUPDATECAPTURE)
|
|
EngFindImageProcAddress(hDxApi, "_DxUpdateCapture");
|
|
|
|
ASSERTGDI(peDirectDrawGlobal->pfnDxApi != NULL,
|
|
"Couldn't find DxApi'");
|
|
ASSERTGDI(peDirectDrawGlobal->pfnAutoflipUpdate != NULL,
|
|
"Couldn't find DxAutoflipUpdate");
|
|
ASSERTGDI(peDirectDrawGlobal->pfnLoseObject != NULL,
|
|
"Couldn't find DxLoseObject");
|
|
ASSERTGDI(peDirectDrawGlobal->pfnEnableIRQ != NULL,
|
|
"Couldn't find DxEnableIRQ");
|
|
ASSERTGDI(peDirectDrawGlobal->pfnUpdateCapture != NULL,
|
|
"Couldn't find DxUpdateCapture");
|
|
ASSERTGDI(pfnDxApiInitialize != NULL,
|
|
"Couldn't find DxApiInitialize");
|
|
|
|
// By explicitly passing dxapi.sys its private win32k.sys
|
|
// entry points, we don't have to export them from win32k.sys,
|
|
// thus preventing any drivers from using those entry points
|
|
// for their own nefarious purposes.
|
|
|
|
pfnDxApiInitialize(DdDxApiOpenDirectDraw,
|
|
DdDxApiOpenVideoPort,
|
|
DdDxApiOpenSurface,
|
|
DdDxApiCloseHandle,
|
|
DdDxApiGetKernelCaps,
|
|
DdDxApiOpenCaptureDevice,
|
|
DdDxApiLockDevice,
|
|
DdDxApiUnlockDevice);
|
|
|
|
// EngLoadImage always makes the entire driver pageable, but
|
|
// DXAPI.SYS handles the DPC for the videoport interrupt and
|
|
// so cannot be entirely pageable. Consequently, we reset
|
|
// the paging now:
|
|
|
|
MmResetDriverPaging(pfnDxApiInitialize);
|
|
|
|
// Now open the DXAPI version of DirectDraw:
|
|
|
|
OpenDirectDrawIn.pfnDirectDrawClose = vDdNullCallBack;
|
|
OpenDirectDrawIn.pContext = NULL;
|
|
OpenDirectDrawIn.dwDirectDrawHandle
|
|
= (ULONG_PTR) peDirectDrawLocal->hGet();
|
|
|
|
peDirectDrawGlobal->pfnDxApi(DD_DXAPI_OPENDIRECTDRAW,
|
|
&OpenDirectDrawIn,
|
|
sizeof(OpenDirectDrawIn),
|
|
&OpenDirectDrawOut,
|
|
sizeof(OpenDirectDrawOut));
|
|
|
|
if (OpenDirectDrawOut.ddRVal == DD_OK)
|
|
{
|
|
// Success!
|
|
peDirectDrawGlobal->hDirectDraw = OpenDirectDrawOut.hDirectDraw;
|
|
}
|
|
|
|
peDirectDrawGlobal->dwDxApiRefCnt = 1;
|
|
}
|
|
else
|
|
{
|
|
WARNING("bDdLoadDxApi: Couldn't load dxapi.sys\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
peDirectDrawGlobal->dwDxApiRefCnt++;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* VOID vDdUnloadDxApi
|
|
*
|
|
* This routine unloads DXAPI.SYS
|
|
*
|
|
* 22-Oct-1997 -by- smac
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdUnloadDxApi(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
|
|
)
|
|
{
|
|
DDCLOSEHANDLE CloseHandle;
|
|
DWORD dwRet;
|
|
|
|
if ((peDirectDrawGlobal->hDxApi != NULL) &&
|
|
(peDirectDrawGlobal->dwDxApiRefCnt > 0 ))
|
|
{
|
|
if( --peDirectDrawGlobal->dwDxApiRefCnt == 0 )
|
|
{
|
|
if (peDirectDrawGlobal->hDirectDraw != NULL)
|
|
{
|
|
CloseHandle.hHandle = peDirectDrawGlobal->hDirectDraw;
|
|
|
|
peDirectDrawGlobal->pfnDxApi(DD_DXAPI_CLOSEHANDLE,
|
|
&CloseHandle,
|
|
sizeof(CloseHandle),
|
|
&dwRet,
|
|
sizeof(dwRet));
|
|
|
|
ASSERTGDI(dwRet == DD_OK, "Unexpected failure from close");
|
|
|
|
peDirectDrawGlobal->hDirectDraw = NULL;
|
|
}
|
|
|
|
vDdUnloadDxApiImage( peDirectDrawGlobal );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* BOOL bDdEnableSoftwareAutoflipping
|
|
*
|
|
* This routine loads up DXAPI.SYS, allocates the non-paged DXAPI structures
|
|
* required for software autoflipping, and enables the videoport interrupt.
|
|
*
|
|
* Returns: FALSE only if a DXAPI resource could not be allocated. May
|
|
* return TRUE even if the interrupt hasn't been successfully
|
|
* enabled (because I expect that interrupts will be usable
|
|
* on the majority of systems that support videoports, and this
|
|
* simplifies other code by allowing it to assume that all the
|
|
* DXAPI structures have been allocated).
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdEnableSoftwareAutoflipping(
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal,
|
|
EDD_VIDEOPORT* peVideoPort,
|
|
DWORD dwVideoPortID,
|
|
BOOL bFirst
|
|
)
|
|
{
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
HANDLE hDxApi;
|
|
PFNDXAPIINITIALIZE pfnDxApiInitialize;
|
|
DDOPENDIRECTDRAWIN OpenDirectDrawIn;
|
|
DDOPENDIRECTDRAWOUT OpenDirectDrawOut;
|
|
DDOPENVIDEOPORTIN OpenVideoPortIn;
|
|
DDOPENVIDEOPORTOUT OpenVideoPortOut;
|
|
DWORD dwRet;
|
|
UNICODE_STRING UnicodeString;
|
|
|
|
DD_ASSERTDEVLOCK(peVideoPort->peDirectDrawGlobal);
|
|
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
|
|
// Create a DXAPI DirectDraw object, which we'll need for software
|
|
// autoflipping.
|
|
|
|
if (bFirst)
|
|
{
|
|
bDdLoadDxApi( peDirectDrawLocal );
|
|
}
|
|
|
|
if (peDirectDrawGlobal->hDirectDraw != NULL)
|
|
{
|
|
ASSERTGDI(peVideoPort->hVideoPort == NULL, "Expected NULL hVideoPort");
|
|
|
|
OpenVideoPortIn.hDirectDraw = peDirectDrawGlobal->hDirectDraw;
|
|
OpenVideoPortIn.pfnVideoPortClose = vDdNullCallBack;
|
|
OpenVideoPortIn.pContext = NULL;
|
|
OpenVideoPortIn.dwVideoPortHandle = dwVideoPortID;
|
|
|
|
peDirectDrawGlobal->pfnDxApi(DD_DXAPI_OPENVIDEOPORT,
|
|
&OpenVideoPortIn,
|
|
sizeof(OpenVideoPortIn),
|
|
&OpenVideoPortOut,
|
|
sizeof(OpenVideoPortOut));
|
|
|
|
if (OpenVideoPortOut.ddRVal == DD_OK)
|
|
{
|
|
peVideoPort->hVideoPort = OpenVideoPortOut.hVideoPort;
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdNotifyEvent
|
|
*
|
|
* This routine calls back to all registered DXAPI clients when a particular
|
|
* event (like mode change notification) occurs.
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdNotifyEvent(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
DWORD dwEvent
|
|
)
|
|
{
|
|
EDD_DXDIRECTDRAW* peDxDirectDraw;
|
|
DXAPI_EVENT* pDxEvent;
|
|
|
|
peDxDirectDraw = peDirectDrawGlobal->peDxDirectDraw;
|
|
|
|
if (peDxDirectDraw != NULL)
|
|
{
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
for (pDxEvent = peDxDirectDraw->pDxEvent_PassiveList;
|
|
pDxEvent != NULL;
|
|
pDxEvent = pDxEvent->pDxEvent_Next)
|
|
{
|
|
if (pDxEvent->dwEvent == dwEvent)
|
|
{
|
|
pDxEvent->pfnCallBack(pDxEvent->dwEvent,pDxEvent->pContext, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DXAPI_OBJECT* pDdDxObjHandleAllocate
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DXOBJ*
|
|
pDdDxObjHandleAllocate(
|
|
DXTYPE iDxType,
|
|
LPDD_NOTIFYCALLBACK pfnClose,
|
|
DWORD dwEvent,
|
|
PVOID pvContext
|
|
)
|
|
{
|
|
DXOBJ* pDxObj;
|
|
|
|
ASSERTGDI(pfnClose != NULL,
|
|
"pDdDxObjHandleAllocate: DXAPI client must supply Close function");
|
|
|
|
pDxObj = (DXOBJ*) PALLOCNONPAGED(sizeof(*pDxObj),'xxdG');
|
|
if (pDxObj != NULL)
|
|
{
|
|
pDxObj->iDxType = iDxType;
|
|
pDxObj->pfnClose = pfnClose;
|
|
pDxObj->pContext = pvContext;
|
|
pDxObj->dwEvent = dwEvent;
|
|
pDxObj->pDxObj_Next = NULL;
|
|
pDxObj->dwFlags = 0;
|
|
pDxObj->pepSession = gpepSession;
|
|
}
|
|
|
|
return(pDxObj);
|
|
}
|
|
|
|
// Should be macro for free build.
|
|
|
|
PVOID
|
|
pDdDxObjDataAllocate(
|
|
ULONG cj,
|
|
ULONG tag
|
|
)
|
|
{
|
|
return (PALLOCNONPAGED(cj,tag));
|
|
}
|
|
|
|
VOID
|
|
vDdDxObjFree(
|
|
PVOID pvDxObj
|
|
)
|
|
{
|
|
VFREEMEM(pvDxObj);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdQueryMiniportDxApiSupport
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdQueryMiniportDxApiSupport(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
|
|
)
|
|
{
|
|
BOOL bMiniportSupport;
|
|
|
|
// Assume failure.
|
|
bMiniportSupport = FALSE;
|
|
|
|
if (bDdIoQueryInterface(peDirectDrawGlobal,
|
|
&GUID_DxApi,
|
|
sizeof(DXAPI_INTERFACE),
|
|
DXAPI_HALVERSION,
|
|
(INTERFACE *)&peDirectDrawGlobal->DxApiInterface))
|
|
{
|
|
ASSERTGDI((peDirectDrawGlobal->DxApiInterface.
|
|
InterfaceReference == NULL) &&
|
|
(peDirectDrawGlobal->DxApiInterface.
|
|
InterfaceDereference == NULL),
|
|
"Miniport shouldn't modify InterfaceReference/Dereference");
|
|
|
|
// Assert some stuff about hooked entry points?
|
|
|
|
peDirectDrawGlobal->HwDeviceExtension
|
|
= peDirectDrawGlobal->DxApiInterface.Context;
|
|
bMiniportSupport = TRUE;
|
|
}
|
|
|
|
// Even if the miniport doesn't support DXAPI accelerations, we still
|
|
// allow DXAPI to work (the DXAPI Lock call doesn't require that the
|
|
// miniport support DXAPI, for example).
|
|
|
|
if (!bMiniportSupport)
|
|
{
|
|
// Zero out any capabilities:
|
|
|
|
RtlZeroMemory(&peDirectDrawGlobal->DxApiInterface,
|
|
sizeof(peDirectDrawGlobal->DxApiInterface));
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD vDdSynchronizeSurface
|
|
*
|
|
* Updates the EDD_DXSURFACE structure using the master EDD_SURFACE
|
|
* structure, with some help from the driver.
|
|
*
|
|
* Analagous to Win95's SyncKernelSurface routine.
|
|
*
|
|
* This routine lets a driver use fields from the larger, pageable version
|
|
* of the DD_SURFACE_* structures used by the display driver to set
|
|
* fields in the smaller, non-pageable version of the corresponding
|
|
* DDSURFACEDATA structure used by the miniport.
|
|
*
|
|
* NOTE: The display driver may NOT use the reserved fields to point to
|
|
* allocated memory, for two reasons:
|
|
*
|
|
* 1. We don't call them when the surfaces is freed, so they'd
|
|
* lose memory;
|
|
* 2. We only let display drivers allocate paged memory, which
|
|
* they can't use in the miniport since they'll be at raised
|
|
* IRQL when we call them.
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdSynchronizeSurface(
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
EDD_DXSURFACE* peDxSurface;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
DD_SYNCSURFACEDATA SyncSurfaceData;
|
|
|
|
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
|
|
|
|
peDxSurface = peSurface->peDxSurface;
|
|
if (peDxSurface != NULL)
|
|
{
|
|
RtlZeroMemory(&SyncSurfaceData, sizeof(SyncSurfaceData));
|
|
|
|
SyncSurfaceData.lpDD = peDirectDrawGlobal;
|
|
SyncSurfaceData.lpDDSurface = peSurface;
|
|
SyncSurfaceData.dwSurfaceOffset = (DWORD) peSurface->fpVidMem;
|
|
SyncSurfaceData.fpLockPtr = peSurface->fpVidMem
|
|
+ (FLATPTR) peDirectDrawGlobal->HalInfo.vmiData.pvPrimary;
|
|
SyncSurfaceData.lPitch = peSurface->lPitch;
|
|
|
|
EDD_DEVLOCK eDevLock(peDirectDrawGlobal);
|
|
|
|
// Call the driver to let it fill in the rest of the values:
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->DxApiCallBacks.SyncSurfaceData))
|
|
{
|
|
peDirectDrawGlobal->
|
|
DxApiCallBacks.SyncSurfaceData(&SyncSurfaceData);
|
|
}
|
|
|
|
// Fields updated by the driver:
|
|
|
|
peDxSurface->dwSurfaceOffset = SyncSurfaceData.dwSurfaceOffset;
|
|
peDxSurface->fpLockPtr = SyncSurfaceData.fpLockPtr;
|
|
peDxSurface->lPitch = SyncSurfaceData.lPitch;
|
|
peDxSurface->dwOverlayOffset = SyncSurfaceData.dwOverlayOffset;
|
|
peDxSurface->dwDriverReserved1 = SyncSurfaceData.dwDriverReserved1;
|
|
peDxSurface->dwDriverReserved2 = SyncSurfaceData.dwDriverReserved2;
|
|
peDxSurface->dwDriverReserved3 = SyncSurfaceData.dwDriverReserved3;
|
|
peDxSurface->dwDriverReserved4 = SyncSurfaceData.dwDriverReserved4;
|
|
|
|
// Fields taken straight from the surface structure:
|
|
|
|
peDxSurface->ddsCaps = peSurface->ddsCaps.dwCaps;
|
|
peDxSurface->dwWidth = peSurface->wWidth;
|
|
peDxSurface->dwHeight = peSurface->wHeight;
|
|
peDxSurface->dwOverlayFlags = peSurface->dwOverlayFlags;
|
|
peDxSurface->dwFormatFlags = peSurface->ddpfSurface.dwFlags;
|
|
peDxSurface->dwFormatFourCC = peSurface->ddpfSurface.dwFourCC;
|
|
peDxSurface->dwFormatBitCount = peSurface->ddpfSurface.dwRGBBitCount;
|
|
peDxSurface->dwRBitMask = peSurface->ddpfSurface.dwRBitMask;
|
|
peDxSurface->dwGBitMask = peSurface->ddpfSurface.dwGBitMask;
|
|
peDxSurface->dwBBitMask = peSurface->ddpfSurface.dwBBitMask;
|
|
peDxSurface->dwOverlaySrcWidth = peSurface->dwOverlaySrcWidth;
|
|
peDxSurface->dwOverlaySrcHeight = peSurface->dwOverlaySrcHeight;
|
|
peDxSurface->dwOverlayDestWidth = peSurface->dwOverlayDestWidth;
|
|
peDxSurface->dwOverlayDestHeight = peSurface->dwOverlayDestHeight;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD vDdSynchronizeVideoPort
|
|
*
|
|
* Updates the EDD_DXVIDEOPORT structure using the master EDD_VIDEOPORT
|
|
* structure, with some help from the driver.
|
|
*
|
|
* Analagous to Win95's SyncKernelVideoPort routine.
|
|
*
|
|
* This routine lets a driver use fields from the larger, pageable version
|
|
* of the DD_VIDEOPORT_LOCAL structure used by the display driver to set
|
|
* fields in the smaller, non-pageable version of the corresponding
|
|
* DDVIDEOPORTDATA structure used by the miniport.
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdSynchronizeVideoPort(
|
|
EDD_VIDEOPORT* peVideoPort
|
|
)
|
|
{
|
|
EDD_DXVIDEOPORT* peDxVideoPort;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
DD_SYNCVIDEOPORTDATA SyncVideoPortData;
|
|
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
|
|
peDxVideoPort = peVideoPort->peDxVideoPort;
|
|
if (peDxVideoPort != NULL)
|
|
{
|
|
RtlZeroMemory(&SyncVideoPortData, sizeof(SyncVideoPortData));
|
|
|
|
SyncVideoPortData.lpDD = peDirectDrawGlobal;
|
|
SyncVideoPortData.lpVideoPort = peVideoPort;
|
|
SyncVideoPortData.dwVBIHeight = peVideoPort->ddvpInfo.dwVBIHeight;
|
|
|
|
if (peVideoPort->ddvpInfo.dwVPFlags & DDVP_PRESCALE)
|
|
{
|
|
SyncVideoPortData.dwHeight = peVideoPort->ddvpInfo.dwPrescaleHeight;
|
|
}
|
|
else if (peVideoPort->ddvpInfo.dwVPFlags & DDVP_CROP)
|
|
{
|
|
SyncVideoPortData.dwHeight = peVideoPort->ddvpInfo.rCrop.bottom -
|
|
peVideoPort->ddvpInfo.rCrop.top;
|
|
}
|
|
else
|
|
{
|
|
SyncVideoPortData.dwHeight = peVideoPort->ddvpDesc.dwFieldHeight;
|
|
}
|
|
if (peVideoPort->ddvpInfo.dwVPFlags & DDVP_INTERLEAVE)
|
|
{
|
|
SyncVideoPortData.dwHeight *= 2;
|
|
}
|
|
|
|
EDD_DEVLOCK eDevLock(peDirectDrawGlobal);
|
|
|
|
// Call the driver to let it fill in the rest of the values:
|
|
|
|
if ((peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->DxApiCallBacks.SyncVideoPortData))
|
|
{
|
|
peDirectDrawGlobal->
|
|
DxApiCallBacks.SyncVideoPortData(&SyncVideoPortData);
|
|
}
|
|
|
|
// Fields updated by the driver:
|
|
|
|
peDxVideoPort->dwOriginOffset = SyncVideoPortData.dwOriginOffset;
|
|
peDxVideoPort->dwHeight = SyncVideoPortData.dwHeight;
|
|
peDxVideoPort->dwVBIHeight = SyncVideoPortData.dwVBIHeight;
|
|
peDxVideoPort->dwDriverReserved1 = SyncVideoPortData.dwDriverReserved1;
|
|
peDxVideoPort->dwDriverReserved2 = SyncVideoPortData.dwDriverReserved2;
|
|
peDxVideoPort->dwDriverReserved3 = SyncVideoPortData.dwDriverReserved3;
|
|
|
|
// Fields taken straight from the videoport structure:
|
|
|
|
peDxVideoPort->dwVideoPortId = peVideoPort->ddvpDesc.dwVideoPortID;
|
|
peDxVideoPort->dwVPFlags = peVideoPort->ddvpInfo.dwVPFlags;
|
|
if( ( peDxVideoPort->dwVBIHeight > 0 ) &&
|
|
( peDxVideoPort->dwVPFlags & DDVP_INTERLEAVE ) &&
|
|
!( peDxVideoPort->dwVPFlags & DDVP_VBINOINTERLEAVE ) )
|
|
{
|
|
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_VBI_INTERLEAVED;
|
|
}
|
|
else
|
|
{
|
|
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_VBI_INTERLEAVED;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HANDLE hDdOpenDxApiSurface
|
|
*
|
|
* Opens a DXAPI representation of a surface
|
|
*
|
|
* 20-Oct-1997 -by- smac
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HANDLE
|
|
hDdOpenDxApiSurface(
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
DDOPENSURFACEIN OpenSurfaceIn;
|
|
DDOPENSURFACEOUT OpenSurfaceOut;
|
|
HANDLE hHandle;
|
|
|
|
hHandle = NULL;
|
|
|
|
// Allocate a DXAPI object:
|
|
|
|
OpenSurfaceIn.hDirectDraw = peSurface->peDirectDrawGlobal->hDirectDraw;
|
|
OpenSurfaceIn.dwSurfaceHandle = (ULONG_PTR) peSurface->hGet();
|
|
OpenSurfaceIn.pfnSurfaceClose = vDdNullCallBack;
|
|
|
|
peSurface->peDirectDrawGlobal->pfnDxApi(DD_DXAPI_OPENSURFACE,
|
|
&OpenSurfaceIn,
|
|
sizeof(OpenSurfaceIn),
|
|
&OpenSurfaceOut,
|
|
sizeof(OpenSurfaceOut));
|
|
|
|
if( ( OpenSurfaceOut.ddRVal == DD_OK ) &&
|
|
( OpenSurfaceOut.hSurface != NULL ) )
|
|
{
|
|
hHandle = OpenSurfaceOut.hSurface;
|
|
vDdSynchronizeSurface( peSurface );
|
|
}
|
|
|
|
return hHandle;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HANDLE hDdCloseDxApiSurface
|
|
*
|
|
* Closes a DXAPI representation of a surface
|
|
*
|
|
* 21-Oct-1997 -by- smac
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdCloseDxApiSurface(
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
DDCLOSEHANDLE CloseHandle;
|
|
DWORD dwRet;
|
|
|
|
CloseHandle.hHandle = peSurface->hSurface;
|
|
|
|
peSurface->peDirectDrawGlobal->pfnDxApi(DD_DXAPI_CLOSEHANDLE,
|
|
&CloseHandle,
|
|
sizeof(CloseHandle),
|
|
&dwRet,
|
|
sizeof(dwRet));
|
|
|
|
ASSERTGDI(dwRet == DD_OK, "Expected DD_OK");
|
|
|
|
peSurface->hSurface = NULL;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdUpdateLinksAndSynchronize
|
|
*
|
|
* A bidirectional link is maintained between a videoport and its active
|
|
* surfaces:
|
|
*
|
|
* 1. From each surface to the active videoport;
|
|
* 2. From the videoport to each of its active surfaces.
|
|
*
|
|
* This routine does all the maintaining of those links, automatically
|
|
* removing links from surfaces that are no longer used, and informing
|
|
* the software autoflipper of the change.
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdUpdateLinksAndSynchronize(
|
|
EDD_VIDEOPORT* peVideoPort,
|
|
BOOL bNewVideo, // FALSE if 'video' parameters should
|
|
EDD_SURFACE** apeNewVideo, // be ignored and current video state
|
|
ULONG cAutoflipVideo, // should remain unchanged
|
|
BOOL bNewVbi, // FALSE if 'VBI' parameters should
|
|
EDD_SURFACE** apeNewVbi, // be ignored and current VBI state
|
|
ULONG cAutoflipVbi // should remain unchanged
|
|
)
|
|
{
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_DXVIDEOPORT* peDxVideoPort;
|
|
// EDD_SURFACE* apeTempVideo[MAX_AUTOFLIP_BUFFERS];
|
|
// EDD_SURFACE* apeTempVbi[MAX_AUTOFLIP_BUFFERS];
|
|
EDD_DXSURFACE* apeDxNewVideo[MAX_AUTOFLIP_BUFFERS];
|
|
EDD_DXSURFACE* apeDxNewVbi[MAX_AUTOFLIP_BUFFERS];
|
|
ULONG i;
|
|
BOOL bOk;
|
|
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
peDxVideoPort = peVideoPort->peDxVideoPort;
|
|
|
|
if (peDxVideoPort == NULL)
|
|
return(TRUE);
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
// First, check to make sure the surfaces have been opened
|
|
|
|
bOk = TRUE;
|
|
for (i = 0; i < cAutoflipVideo; i++)
|
|
{
|
|
if( ( apeNewVideo[i] == NULL ) ||
|
|
( apeNewVideo[i]->hSurface == NULL ) )
|
|
{
|
|
bOk = FALSE;
|
|
}
|
|
}
|
|
for (i = 0; i < cAutoflipVbi; i++)
|
|
{
|
|
if( ( apeNewVbi[i] == NULL ) ||
|
|
( apeNewVbi[i]->hSurface == NULL ) )
|
|
{
|
|
bOk = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!bOk)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// Remove the videoport links from the old surfaces, and stash a copy
|
|
// of the list for later:
|
|
|
|
for (i = 0; i < peVideoPort->cAutoflipVideo; i++)
|
|
{
|
|
peVideoPort->apeSurfaceVideo[i]->lpVideoPort = NULL;
|
|
if( peVideoPort->apeSurfaceVideo[i]->peDxSurface != NULL )
|
|
{
|
|
peVideoPort->apeSurfaceVideo[i]->peDxSurface->peDxVideoPort = NULL;
|
|
}
|
|
}
|
|
for (i = 0; i < peVideoPort->cAutoflipVbi; i++)
|
|
{
|
|
peVideoPort->apeSurfaceVbi[i]->lpVideoPort = NULL;
|
|
if( peVideoPort->apeSurfaceVbi[i]->peDxSurface != NULL )
|
|
{
|
|
peVideoPort->apeSurfaceVbi[i]->peDxSurface->peDxVideoPort = NULL;
|
|
}
|
|
}
|
|
|
|
// Now add the links to the new surfaces:
|
|
|
|
for (i = 0; i < cAutoflipVideo; i++)
|
|
{
|
|
peVideoPort->apeSurfaceVideo[i] = apeNewVideo[i];
|
|
apeNewVideo[i]->lpVideoPort = peVideoPort;
|
|
apeDxNewVideo[i] = apeNewVideo[i]->peDxSurface;
|
|
}
|
|
for (i = 0; i < cAutoflipVbi; i++)
|
|
{
|
|
peVideoPort->apeSurfaceVbi[i] = apeNewVbi[i];
|
|
apeNewVbi[i]->lpVideoPort = peVideoPort;
|
|
apeDxNewVbi[i] = apeNewVbi[i]->peDxSurface;
|
|
}
|
|
|
|
// Now modify the autoflip buffers, being careful to synchronize with
|
|
// the software-autoflip DPC. Note that this does stuff like sets
|
|
// peDxVideoPort->cAutoflipVbi.
|
|
|
|
peDirectDrawGlobal->pfnAutoflipUpdate(peDxVideoPort,
|
|
apeDxNewVideo,
|
|
cAutoflipVideo,
|
|
apeDxNewVbi,
|
|
cAutoflipVbi);
|
|
|
|
peVideoPort->cAutoflipVideo = cAutoflipVideo;
|
|
peVideoPort->cAutoflipVbi = cAutoflipVbi;
|
|
|
|
// Finally, Update some last public fields in the videoport structure:
|
|
|
|
peVideoPort->dwNumAutoflip = cAutoflipVideo;
|
|
peVideoPort->dwNumVBIAutoflip = cAutoflipVbi;
|
|
peVideoPort->lpSurface = (cAutoflipVideo == 0) ? NULL : apeNewVideo[0];
|
|
peVideoPort->lpVBISurface = (cAutoflipVbi == 0) ? NULL : apeNewVbi[0];
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdDxApiFreeDirectDraw
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdDxApiFreeDirectDraw(
|
|
DXOBJ* pDxObj,
|
|
BOOL bDoCallBack
|
|
)
|
|
{
|
|
EDD_DXDIRECTDRAW* peDxDirectDraw;
|
|
DXOBJ* pDxTmp;
|
|
|
|
ASSERTGDI(pDxObj->iDxType == DXT_DIRECTDRAW, "Invalid object");
|
|
|
|
peDxDirectDraw = pDxObj->peDxDirectDraw;
|
|
|
|
EDD_DEVLOCK eDevLock(peDxDirectDraw->hdev);
|
|
|
|
if (bDoCallBack)
|
|
{
|
|
pDxObj->pfnClose(pDxObj->dwEvent,pDxObj->pContext, 0, 0);
|
|
}
|
|
|
|
// Remove this DXOBJ instance from the list hanging off the DXAPI object:
|
|
|
|
if (peDxDirectDraw->pDxObj_List == pDxObj)
|
|
{
|
|
peDxDirectDraw->pDxObj_List = pDxObj->pDxObj_Next;
|
|
}
|
|
else
|
|
{
|
|
for (pDxTmp = peDxDirectDraw->pDxObj_List;
|
|
pDxTmp->pDxObj_Next != pDxObj;
|
|
pDxTmp = pDxTmp->pDxObj_Next)
|
|
{
|
|
ASSERTGDI(pDxTmp->iDxType == DXT_DIRECTDRAW, "Unexpected type");
|
|
ASSERTGDI(pDxTmp->pDxObj_Next != NULL, "Couldn't find node");
|
|
}
|
|
|
|
pDxTmp->pDxObj_Next = pDxObj->pDxObj_Next;
|
|
}
|
|
|
|
// Free the DXOBJ instance:
|
|
|
|
pDxObj->iDxType = DXT_INVALID;
|
|
vDdDxObjFree(pDxObj);
|
|
|
|
// If there are no more DXOBJ instances of the DirectDraw DXAPI object,
|
|
// we can free the non-paged DXAPI part of the DirectDraw structure:
|
|
|
|
if (peDxDirectDraw->pDxObj_List == NULL)
|
|
{
|
|
if ((peDxDirectDraw->pDxEvent_PassiveList != NULL) ||
|
|
(peDxDirectDraw->pDxEvent_DispatchList[CLIENT_DISPATCH_LIST] != NULL))
|
|
{
|
|
KdPrint(("vDdDxApiFreeDirectDraw: A kernel-mode DXAPI client didn't unregister all\n"));
|
|
KdPrint((" its events when it received CLOSE call-backs. This will cause at\n"));
|
|
KdPrint((" best a memory leak and at worst a crash!\n"));
|
|
RIP("The DXAPI client must be fixed.");
|
|
}
|
|
|
|
if (peDxDirectDraw->peDirectDrawGlobal != NULL)
|
|
{
|
|
peDxDirectDraw->peDirectDrawGlobal->peDxDirectDraw = NULL;
|
|
}
|
|
vDdDxObjFree(peDxDirectDraw);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdDxApiFreeVideoPort
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdDxApiFreeVideoPort(
|
|
DXOBJ* pDxObj,
|
|
BOOL bDoCallBack
|
|
)
|
|
{
|
|
EDD_DXDIRECTDRAW* peDxDirectDraw;
|
|
EDD_DXVIDEOPORT* peDxVideoPort;
|
|
DXOBJ* pDxObjTmp;
|
|
DXAPI_EVENT* pDxEventTmp;
|
|
|
|
ASSERTGDI(pDxObj->iDxType == DXT_VIDEOPORT, "Invalid object");
|
|
|
|
peDxVideoPort = pDxObj->peDxVideoPort;
|
|
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
|
|
|
|
EDD_DEVLOCK eDevLock(peDxDirectDraw->hdev);
|
|
|
|
if (bDoCallBack)
|
|
{
|
|
pDxObj->pfnClose(pDxObj->dwEvent, pDxObj->pContext, 0, 0);
|
|
}
|
|
|
|
// Remove this DXOBJ instance from the list hanging off the DXAPI object:
|
|
|
|
if (peDxVideoPort->pDxObj_List == pDxObj)
|
|
{
|
|
peDxVideoPort->pDxObj_List = pDxObj->pDxObj_Next;
|
|
}
|
|
else
|
|
{
|
|
for (pDxObjTmp = peDxVideoPort->pDxObj_List;
|
|
pDxObjTmp->pDxObj_Next != pDxObj;
|
|
pDxObjTmp = pDxObjTmp->pDxObj_Next)
|
|
{
|
|
ASSERTGDI(pDxObjTmp->iDxType == DXT_VIDEOPORT, "Unexpected type");
|
|
ASSERTGDI(pDxObjTmp->pDxObj_Next != NULL, "Couldn't find node");
|
|
}
|
|
|
|
pDxObjTmp->pDxObj_Next = pDxObj->pDxObj_Next;
|
|
}
|
|
|
|
// Free the notification event if one is present
|
|
|
|
if (peDxVideoPort->pNotifyEvent != NULL)
|
|
{
|
|
PKEVENT pTemp = NULL;
|
|
HANDLE hEvent = peDxVideoPort->pNotifyEventHandle;
|
|
NTSTATUS Status;
|
|
|
|
peDxVideoPort->pNotifyEvent = NULL;
|
|
peDxVideoPort->pNotifyEventHandle = NULL;
|
|
|
|
// Make sure that the handle hasn't been freed by the OS already
|
|
Status = ObReferenceObjectByHandle( hEvent,
|
|
0,
|
|
0,
|
|
KernelMode,
|
|
(PVOID *) &pTemp,
|
|
NULL );
|
|
if ((pTemp != NULL) && (Status != STATUS_INVALID_HANDLE))
|
|
{
|
|
ObDereferenceObject(pTemp);
|
|
ZwClose (hEvent);
|
|
}
|
|
|
|
// Un-page lock memory
|
|
|
|
peDxVideoPort->pNotifyBuffer = NULL;
|
|
if (peDxVideoPort->pNotifyMdl != NULL)
|
|
{
|
|
MmUnlockPages (peDxVideoPort->pNotifyMdl);
|
|
IoFreeMdl (peDxVideoPort->pNotifyMdl);
|
|
peDxVideoPort->pNotifyMdl = NULL;
|
|
}
|
|
}
|
|
|
|
// Free the DXOBJ instance:
|
|
|
|
pDxObj->iDxType = DXT_INVALID;
|
|
vDdDxObjFree(pDxObj);
|
|
|
|
// If there are no more DXOBJ instances of the VideoPort DXAPI object,
|
|
// we can free the non-paged DXAPI part of the VideoPort structure:
|
|
|
|
if (peDxVideoPort->pDxObj_List == NULL)
|
|
{
|
|
ASSERTGDI(peDxDirectDraw != NULL, "Unexpected NULL peDxDirectDraw");
|
|
|
|
for (pDxEventTmp = peDxDirectDraw->pDxEvent_DispatchList[CLIENT_DISPATCH_LIST];
|
|
pDxEventTmp != NULL;
|
|
pDxEventTmp = pDxEventTmp->pDxEvent_Next)
|
|
{
|
|
if (pDxEventTmp->peDxVideoPort == peDxVideoPort)
|
|
{
|
|
KdPrint(("vDdDxApiFreeVideoPort: A kernel-mode DXAPI client didn't unregister all\n"));
|
|
KdPrint((" its videoport events when it received CLOSE call-backs. This will\n"));
|
|
KdPrint((" cause at best a memory leak and at worst a crash!\n"));
|
|
RIP("The DXAPI client must be fixed.");
|
|
}
|
|
}
|
|
|
|
if (peDxVideoPort->peVideoPort != NULL)
|
|
{
|
|
// If we are actually freeing the video port, we need to lose
|
|
// any capture objects that are associated with it
|
|
|
|
while( peDxVideoPort->peDxCapture != NULL )
|
|
{
|
|
vDdLoseDxObjects( peDxDirectDraw->peDirectDrawGlobal,
|
|
peDxVideoPort->peDxCapture->pDxObj_List,
|
|
(PVOID) peDxVideoPort->peDxCapture,
|
|
LO_CAPTURE );
|
|
}
|
|
|
|
peDxVideoPort->peVideoPort->peDxVideoPort = NULL;
|
|
}
|
|
vDdDxObjFree(peDxVideoPort);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdDxApiFreeCapture
|
|
*
|
|
* 10-Apr-1998 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdDxApiFreeCapture(
|
|
DXOBJ* pDxObj,
|
|
BOOL bDoCallBack
|
|
)
|
|
{
|
|
EDD_DXCAPTURE* peDxCapture;
|
|
EDD_DXVIDEOPORT* peDxVideoPort;
|
|
|
|
ASSERTGDI(pDxObj->iDxType == DXT_CAPTURE, "Invalid object");
|
|
|
|
peDxCapture = pDxObj->peDxCapture;
|
|
peDxVideoPort = peDxCapture->peDxVideoPort;
|
|
|
|
if (bDoCallBack)
|
|
{
|
|
pDxObj->pfnClose(pDxObj->dwEvent, pDxObj->pContext, 0, 0);
|
|
}
|
|
|
|
// Free the DXOBJ instance:
|
|
|
|
pDxObj->iDxType = DXT_INVALID;
|
|
vDdDxObjFree(pDxObj);
|
|
|
|
// Unassociate the capture object from the video port. Since this
|
|
// must be synchronized with the DPC, we need to call DxApi to do this.
|
|
|
|
if( peDxVideoPort != NULL )
|
|
{
|
|
EDD_DXDIRECTDRAW* peDxDirectDraw;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peDxDirectDraw = peDxVideoPort->peDxDirectDraw;
|
|
EDD_DEVLOCK eDevLock(peDxDirectDraw->hdev);
|
|
peDirectDrawGlobal = peDxDirectDraw->peDirectDrawGlobal;
|
|
peDirectDrawGlobal->pfnUpdateCapture( peDxVideoPort,
|
|
peDxCapture, TRUE );
|
|
}
|
|
|
|
vDdDxObjFree(peDxCapture);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdDxApiFreeSurface
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdDxApiFreeSurface(
|
|
DXOBJ* pDxObj,
|
|
BOOL bDoCallBack
|
|
)
|
|
{
|
|
EDD_DXSURFACE* peDxSurface;
|
|
EDD_DXDIRECTDRAW* peDxDirectDraw;
|
|
DXOBJ* pDxTmp;
|
|
|
|
ASSERTGDI(pDxObj->iDxType == DXT_SURFACE, "Invalid object");
|
|
|
|
peDxSurface = pDxObj->peDxSurface;
|
|
peDxDirectDraw = peDxSurface->peDxDirectDraw;
|
|
|
|
EDD_DEVLOCK eDevLock(peDxDirectDraw->hdev);
|
|
|
|
if (bDoCallBack)
|
|
{
|
|
pDxObj->pfnClose(pDxObj->dwEvent, pDxObj->pContext, 0, 0);
|
|
}
|
|
|
|
// Remove this DXOBJ instance from the list hanging off the DXAPI object:
|
|
|
|
if (peDxSurface->pDxObj_List == pDxObj)
|
|
{
|
|
peDxSurface->pDxObj_List = pDxObj->pDxObj_Next;
|
|
}
|
|
else
|
|
{
|
|
for (pDxTmp = peDxSurface->pDxObj_List;
|
|
pDxTmp->pDxObj_Next != pDxObj;
|
|
pDxTmp = pDxTmp->pDxObj_Next)
|
|
{
|
|
ASSERTGDI(pDxTmp->iDxType == DXT_SURFACE, "Unexpected type");
|
|
ASSERTGDI(pDxTmp->pDxObj_Next != NULL, "Couldn't find node");
|
|
}
|
|
|
|
pDxTmp->pDxObj_Next = pDxObj->pDxObj_Next;
|
|
}
|
|
|
|
// Free the DXOBJ instance:
|
|
|
|
pDxObj->iDxType = DXT_INVALID;
|
|
vDdDxObjFree(pDxObj);
|
|
|
|
// If there are no more DXOBJ instances of the Surface DXAPI object,
|
|
// we can free the non-paged DXAPI part of the Surface structure:
|
|
|
|
if (peDxSurface->pDxObj_List == NULL)
|
|
{
|
|
if (peDxSurface->peSurface != NULL)
|
|
{
|
|
peDxSurface->peSurface->peDxSurface = NULL;
|
|
}
|
|
vDdDxObjFree(peDxSurface);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdStopVideoPort
|
|
*
|
|
* Makes an emergency stop of the videoport.
|
|
*
|
|
* 16-Feb-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdStopVideoPort(
|
|
EDD_VIDEOPORT* peVideoPort
|
|
)
|
|
{
|
|
EDD_DXVIDEOPORT* peDxVideoPort;
|
|
DD_UPDATEVPORTDATA UpdateVPortData;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
BOOL b;
|
|
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
peDxVideoPort = peVideoPort->peDxVideoPort;
|
|
|
|
// Stop the videoport itself:
|
|
|
|
UpdateVPortData.lpDD = peDirectDrawGlobal;
|
|
UpdateVPortData.lpVideoPort = peVideoPort;
|
|
UpdateVPortData.lplpDDVBISurface = NULL;
|
|
UpdateVPortData.lplpDDSurface = NULL;
|
|
UpdateVPortData.lpVideoInfo = NULL;
|
|
UpdateVPortData.dwNumAutoflip = 0;
|
|
UpdateVPortData.dwFlags = DDRAWI_VPORTSTOP;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
ASSERTGDI(peDirectDrawGlobal->VideoPortCallBacks.UpdateVideoPort != NULL,
|
|
"Videoport object shouldn't have been created if UpdateVideoPort NULL");
|
|
|
|
// Disable video port VSYNC IRQ
|
|
|
|
if (peDxVideoPort != NULL)
|
|
{
|
|
// Shut down software autoflipping (the autoflipping routine peeks
|
|
// at these values, so this is sufficient):
|
|
|
|
peDxVideoPort->bSoftwareAutoflip = FALSE;
|
|
peDxVideoPort->flFlags &= ~(DD_DXVIDEOPORT_FLAG_AUTOFLIP|DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI);
|
|
peDxVideoPort->bSkip = FALSE;
|
|
peDxVideoPort->dwSetStateField = 0;
|
|
|
|
if (peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_ON)
|
|
{
|
|
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_ON;
|
|
peDirectDrawGlobal->pfnEnableIRQ(peDxVideoPort, FALSE );
|
|
}
|
|
}
|
|
|
|
|
|
if (!peDirectDrawGlobal->bSuspended &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.UpdateVideoPort != NULL))
|
|
{
|
|
peDirectDrawGlobal->VideoPortCallBacks.UpdateVideoPort(&UpdateVPortData);
|
|
}
|
|
|
|
// Update the links to reflect the fact that no surface is a
|
|
// destination for this videoport anymore:
|
|
|
|
b = bDdUpdateLinksAndSynchronize(peVideoPort, TRUE, NULL, 0, TRUE, NULL, 0);
|
|
|
|
ASSERTGDI(b, "vDdStopVideoPort: Shouldn't fail bDdUpdateLinkAndSynchronize");
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID LoseDxObjects
|
|
*
|
|
* Notifies all clients using the resource that it can't be used anymore.
|
|
* It also notifies DXAPI.SYS that the resource is unusable.
|
|
*
|
|
* 04-Nov-1997 -by- smac
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdLoseDxObjects(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
DXOBJ* pDxObj,
|
|
PVOID pDxThing,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
if( pDxObj != NULL )
|
|
{
|
|
while( pDxObj != NULL )
|
|
{
|
|
pDxObj->pfnClose(pDxObj->dwEvent, pDxObj->pContext, 0, 0);
|
|
pDxObj = pDxObj->pDxObj_Next;
|
|
}
|
|
|
|
peDirectDrawGlobal->pfnLoseObject( pDxThing, (LOTYPE) dwType );
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdDeleteVideoPortObject
|
|
*
|
|
* Deletes a kernel-mode representation of the videoport object.
|
|
*
|
|
* 16-Feb-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdDeleteVideoPortObject(
|
|
HANDLE hVideoPort,
|
|
DWORD* pdwRet // For returning driver return code, may be NULL
|
|
)
|
|
{
|
|
BOOL bRet;
|
|
DWORD dwRet;
|
|
EDD_DXVIDEOPORT* peDxVideoPort;
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_VIDEOPORT* peTmp;
|
|
VOID* pvRemove;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
DD_DESTROYVPORTDATA DestroyVPortData;
|
|
DXOBJ* pDxObj;
|
|
DXOBJ* pDxObjNext;
|
|
|
|
bRet = FALSE;
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
|
|
peVideoPort = (EDD_VIDEOPORT*) DdHmgLock((HDD_OBJ) hVideoPort, DD_VIDEOPORT_TYPE, FALSE);
|
|
|
|
if (peVideoPort != NULL)
|
|
{
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
|
|
// Make sure the videoport has been turned off:
|
|
|
|
vDdStopVideoPort(peVideoPort);
|
|
|
|
// If there are any capture objects associated witht he video port,
|
|
// lose them now
|
|
|
|
peDxVideoPort = peVideoPort->peDxVideoPort;
|
|
while( peDxVideoPort && (peDxVideoPort->peDxCapture != NULL) )
|
|
{
|
|
vDdLoseDxObjects( peDirectDrawGlobal,
|
|
peDxVideoPort->peDxCapture->pDxObj_List,
|
|
(PVOID) peDxVideoPort->peDxCapture,
|
|
LO_CAPTURE );
|
|
}
|
|
|
|
// Free the DXAPI instance of the videoport object
|
|
|
|
if (peVideoPort->hVideoPort != NULL)
|
|
{
|
|
vDdDxApiFreeVideoPort( (DXOBJ*) peVideoPort->hVideoPort, FALSE);
|
|
peVideoPort->hVideoPort = NULL;
|
|
peDxVideoPort = peVideoPort->peDxVideoPort;
|
|
}
|
|
|
|
// Notify clients that their open objects are lost
|
|
|
|
if (peDxVideoPort) {
|
|
vDdLoseDxObjects( peDirectDrawGlobal,
|
|
peDxVideoPort->pDxObj_List,
|
|
(PVOID) peDxVideoPort,
|
|
LO_VIDEOPORT );
|
|
}
|
|
|
|
pvRemove = DdHmgRemoveObject((HDD_OBJ) hVideoPort,
|
|
DdHmgQueryLock((HDD_OBJ) hVideoPort),
|
|
0,
|
|
TRUE,
|
|
DD_VIDEOPORT_TYPE);
|
|
|
|
ASSERTGDI(pvRemove != NULL, "Outstanding surfaces locks");
|
|
|
|
// Hold the devlock while we call the driver and while we muck
|
|
// around in the videoport list:
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (peVideoPort->fl & DD_VIDEOPORT_FLAG_DRIVER_CREATED)
|
|
{
|
|
// Call the driver if it created the object:
|
|
|
|
if (peDirectDrawGlobal->VideoPortCallBacks.DestroyVideoPort)
|
|
{
|
|
DestroyVPortData.lpDD = peDirectDrawGlobal;
|
|
DestroyVPortData.lpVideoPort = peVideoPort;
|
|
DestroyVPortData.ddRVal = DDERR_GENERIC;
|
|
|
|
dwRet = peDirectDrawGlobal->
|
|
VideoPortCallBacks.DestroyVideoPort(&DestroyVPortData);
|
|
}
|
|
}
|
|
|
|
// Remove from the videoport linked-list:
|
|
|
|
peDirectDrawLocal = peVideoPort->peDirectDrawLocal;
|
|
|
|
if (peDirectDrawLocal->peVideoPort_DdList == peVideoPort)
|
|
{
|
|
peDirectDrawLocal->peVideoPort_DdList
|
|
= peVideoPort->peVideoPort_DdNext;
|
|
}
|
|
else
|
|
{
|
|
for (peTmp = peDirectDrawLocal->peVideoPort_DdList;
|
|
peTmp->peVideoPort_DdNext != peVideoPort;
|
|
peTmp = peTmp->peVideoPort_DdNext)
|
|
;
|
|
|
|
peTmp->peVideoPort_DdNext = peVideoPort->peVideoPort_DdNext;
|
|
}
|
|
|
|
// Unload DXAPI.SYS if no other video port is using it
|
|
|
|
if (peDirectDrawLocal->peVideoPort_DdList == NULL)
|
|
{
|
|
vDdUnloadDxApi( peDirectDrawGlobal );
|
|
}
|
|
|
|
// We're all done with this object, so free the memory and
|
|
// leave:
|
|
|
|
DdFreeObject(peVideoPort, DD_VIDEOPORT_TYPE);
|
|
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING1("bDdDeleteVideoPortObject: Bad handle or object was busy\n");
|
|
}
|
|
|
|
if (pdwRet != NULL)
|
|
{
|
|
*pdwRet = dwRet;
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DdDxApiOpenDirectDraw
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
APIENTRY
|
|
DdDxApiOpenDirectDraw(
|
|
DDOPENDIRECTDRAWIN* pOpenDirectDrawIn,
|
|
DDOPENDIRECTDRAWOUT* pOpenDirectDrawOut,
|
|
PKDEFERRED_ROUTINE pfnEventDpc,
|
|
ULONG DxApiPrivateVersionNumber
|
|
)
|
|
{
|
|
HANDLE hDirectDraw;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
DXOBJ* pDxObj;
|
|
EDD_DXDIRECTDRAW* peDxDirectDraw;
|
|
|
|
ASSERTGDI(KeGetCurrentIrql() == PASSIVE_LEVEL,
|
|
"DdDxApiOpenDirectDraw: Callable only at passive level (it's not pageable)");
|
|
|
|
hDirectDraw = 0; // Assume failure
|
|
|
|
// We use the private version number to ensure consistency between
|
|
// win32k.sys and dxapi.sys. Since dxapi.sys is dynamically loaded,
|
|
// I am worried about a scenario where a service pack is applied that
|
|
// updates both dxapi.sys and win32k.sys -- if the machine isn't
|
|
// rebooted, the old win32k.sys will remain loaded but the new dxapi.sys
|
|
// may be loaded, possibly causing a crash.
|
|
|
|
peDirectDrawLocal
|
|
= eLockDirectDraw.peLock((HANDLE) pOpenDirectDrawIn->dwDirectDrawHandle);
|
|
if ((peDirectDrawLocal != NULL) ||
|
|
(DxApiPrivateVersionNumber != DXAPI_PRIVATE_VERSION_NUMBER))
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
pDxObj = pDdDxObjHandleAllocate(DXT_DIRECTDRAW,
|
|
pOpenDirectDrawIn->pfnDirectDrawClose,
|
|
DDNOTIFY_CLOSEDIRECTDRAW,
|
|
pOpenDirectDrawIn->pContext);
|
|
if (pDxObj != NULL)
|
|
{
|
|
// Among other things, enforce synchronization while we muck
|
|
// around in the global DirectDraw object:
|
|
|
|
EDD_DEVLOCK eDevLock(peDirectDrawGlobal);
|
|
|
|
peDxDirectDraw = peDirectDrawGlobal->peDxDirectDraw;
|
|
if (peDxDirectDraw != NULL)
|
|
{
|
|
// Just add this object to the list hanging off the DirectDraw
|
|
// object:
|
|
|
|
pDxObj->peDxDirectDraw = peDxDirectDraw;
|
|
pDxObj->pDxObj_Next = peDxDirectDraw->pDxObj_List;
|
|
peDxDirectDraw->pDxObj_List = pDxObj;
|
|
|
|
// Success!
|
|
|
|
hDirectDraw = (HANDLE) pDxObj;
|
|
}
|
|
else
|
|
{
|
|
peDxDirectDraw = (EDD_DXDIRECTDRAW*) pDdDxObjDataAllocate(
|
|
sizeof(*peDxDirectDraw),
|
|
'dxdG');
|
|
if (peDxDirectDraw)
|
|
{
|
|
RtlZeroMemory(peDxDirectDraw, sizeof(*peDxDirectDraw));
|
|
|
|
pDxObj->peDxDirectDraw = peDxDirectDraw;
|
|
|
|
// We need to access some capabilities at raised IRQL,
|
|
// so copy those from the paged 'peDirectDrawGlobal'
|
|
// to the non-paged 'peDxDirectDraw' now:
|
|
|
|
peDxDirectDraw->DxApiInterface
|
|
= peDirectDrawGlobal->DxApiInterface;
|
|
peDxDirectDraw->HwDeviceExtension
|
|
= peDirectDrawGlobal->HwDeviceExtension;
|
|
peDxDirectDraw->dwIRQCaps
|
|
= peDirectDrawGlobal->DDKernelCaps.dwIRQCaps;
|
|
peDxDirectDraw->peDirectDrawGlobal
|
|
= peDirectDrawGlobal;
|
|
peDxDirectDraw->hdev
|
|
= peDirectDrawGlobal->hdev;
|
|
|
|
peDirectDrawGlobal->peDxDirectDraw = peDxDirectDraw;
|
|
|
|
peDxDirectDraw->pDxObj_List = pDxObj;
|
|
|
|
// Initialize our kernel structures use for interrupts
|
|
// and handling raised IRQL callers.
|
|
|
|
KeInitializeDpc(&peDxDirectDraw->EventDpc,
|
|
pfnEventDpc,
|
|
peDxDirectDraw);
|
|
|
|
KeInitializeSpinLock(&peDxDirectDraw->SpinLock);
|
|
|
|
// Success!
|
|
|
|
hDirectDraw = (HANDLE) pDxObj;
|
|
}
|
|
}
|
|
|
|
if (!hDirectDraw)
|
|
{
|
|
vDdDxObjFree(pDxObj);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DdDxApiOpenDirectDraw: Invalid dwDirectDrawHandle, failing\n");
|
|
}
|
|
|
|
pOpenDirectDrawOut->hDirectDraw = hDirectDraw;
|
|
pOpenDirectDrawOut->ddRVal = (hDirectDraw != NULL) ? DD_OK : DDERR_GENERIC;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DdDxApiOpenVideoPort
|
|
*
|
|
* This routine lets a driver use fields from the larger, pageable version
|
|
* of the DD_SURFACE_* structures used by the display driver to set
|
|
* fields in the smaller, non-pageable version of the corresponding
|
|
* DDSURFACEDATA structure used by the miniport.
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
APIENTRY
|
|
DdDxApiOpenVideoPort(
|
|
DDOPENVIDEOPORTIN* pOpenVideoPortIn,
|
|
DDOPENVIDEOPORTOUT* pOpenVideoPortOut
|
|
)
|
|
{
|
|
HANDLE hVideoPort;
|
|
DXOBJ* pDxObjDirectDraw;
|
|
DXOBJ* pDxObj;
|
|
EDD_DXDIRECTDRAW* peDxDirectDraw;
|
|
EDD_DXVIDEOPORT* peDxVideoPort;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_LOCK_VIDEOPORT eLockVideoPort;
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
BOOL bFound;
|
|
EDD_DIRECTDRAW_LOCAL* peTempDirectDrawLocal;
|
|
EDD_VIDEOPORT* peTempVideoPort;
|
|
|
|
|
|
ASSERTGDI(KeGetCurrentIrql() == PASSIVE_LEVEL,
|
|
"DdDxApiOpenVideoPort: Callable only at passive level (it's not pageable)");
|
|
|
|
hVideoPort = 0; // Assume failure
|
|
|
|
pDxObjDirectDraw = (DXOBJ*) pOpenVideoPortIn->hDirectDraw;
|
|
|
|
ASSERTGDI((pDxObjDirectDraw != NULL) &&
|
|
(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW),
|
|
"DdDxApiOpenVideoPort: Invalid hDirectDraw, we're about to crash");
|
|
|
|
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
|
|
|
|
// Among other things, enforce synchronization while we muck around
|
|
// in the DirectDraw object:
|
|
|
|
EDD_DEVLOCK eDevLock(peDxDirectDraw->hdev);
|
|
|
|
if (!peDxDirectDraw->bLost)
|
|
{
|
|
peDirectDrawGlobal = peDxDirectDraw->peDirectDrawGlobal;
|
|
|
|
// We need to get a handle to the video port, so we need to
|
|
// go looking for it.
|
|
|
|
bFound = FALSE;
|
|
peTempDirectDrawLocal = peDirectDrawGlobal->peDirectDrawLocalList;
|
|
while( ( peTempDirectDrawLocal != NULL ) && !bFound )
|
|
{
|
|
peTempVideoPort = peTempDirectDrawLocal->peVideoPort_DdList;
|
|
while( peTempVideoPort != NULL )
|
|
{
|
|
if( peTempVideoPort->ddvpDesc.dwVideoPortID == pOpenVideoPortIn->dwVideoPortHandle )
|
|
{
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
peTempVideoPort = peTempVideoPort->peVideoPort_DdNext;
|
|
}
|
|
peTempDirectDrawLocal = peTempDirectDrawLocal->peDirectDrawLocalNext;
|
|
}
|
|
if( bFound )
|
|
{
|
|
peVideoPort = eLockVideoPort.peLock(
|
|
(HANDLE) peTempVideoPort->hGet());
|
|
if ((peVideoPort != NULL) &&
|
|
(peVideoPort->peDirectDrawGlobal == peDirectDrawGlobal))
|
|
{
|
|
pDxObj = pDdDxObjHandleAllocate(DXT_VIDEOPORT,
|
|
pOpenVideoPortIn->pfnVideoPortClose,
|
|
DDNOTIFY_CLOSEVIDEOPORT,
|
|
pOpenVideoPortIn->pContext);
|
|
if (pDxObj != NULL)
|
|
{
|
|
|
|
peDxVideoPort = peVideoPort->peDxVideoPort;
|
|
if (peDxVideoPort != NULL)
|
|
{
|
|
// Just add this object to the list hanging off the
|
|
// surface object:
|
|
|
|
pDxObj->peDxVideoPort = peDxVideoPort;
|
|
pDxObj->pDxObj_Next = peDxVideoPort->pDxObj_List;
|
|
peDxVideoPort->pDxObj_List = pDxObj;
|
|
|
|
// Success!
|
|
|
|
hVideoPort = (HANDLE) pDxObj;
|
|
}
|
|
else
|
|
{
|
|
peDxVideoPort = (EDD_DXVIDEOPORT*) pDdDxObjDataAllocate(
|
|
sizeof(*peDxVideoPort),
|
|
'sxdG');
|
|
if (peDxVideoPort)
|
|
{
|
|
RtlZeroMemory(peDxVideoPort, sizeof(*peDxVideoPort));
|
|
|
|
pDxObj->peDxVideoPort = peDxVideoPort;
|
|
|
|
peVideoPort->peDxVideoPort = peDxVideoPort;
|
|
|
|
peDxVideoPort->pDxObj_List = pDxObj;
|
|
peDxVideoPort->peVideoPort = peVideoPort;
|
|
peDxVideoPort->peDxDirectDraw = peDxDirectDraw;
|
|
|
|
peDxVideoPort->iCurrentVideo = 1;
|
|
peDxVideoPort->dwVideoPortID
|
|
= peVideoPort->ddvpDesc.dwVideoPortID;
|
|
|
|
vDdSynchronizeVideoPort(peVideoPort);
|
|
|
|
// Success!
|
|
|
|
hVideoPort = (HANDLE) pDxObj;
|
|
}
|
|
}
|
|
|
|
if (!hVideoPort)
|
|
{
|
|
vDdDxObjFree(pDxObj);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DdDxApiOpenVideoPort: Invalid dwSurfaceHandle, failing.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DdDxApiOpenVideoPort: Invalid dwSurfaceHandle, failing.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DdDxApiOpenVideoPort: DirectDraw object is lost");
|
|
}
|
|
|
|
pOpenVideoPortOut->hVideoPort = hVideoPort;
|
|
pOpenVideoPortOut->ddRVal = (hVideoPort != NULL) ? DD_OK : DDERR_GENERIC;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DdDxApiOpenSurface
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
APIENTRY
|
|
DdDxApiOpenSurface(
|
|
DDOPENSURFACEIN* pOpenSurfaceIn,
|
|
DDOPENSURFACEOUT* pOpenSurfaceOut
|
|
)
|
|
{
|
|
HANDLE hSurface;
|
|
DXOBJ* pDxObjDirectDraw;
|
|
DXOBJ* pDxObj;
|
|
EDD_DXDIRECTDRAW* peDxDirectDraw;
|
|
EDD_DXSURFACE* peDxSurface;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_SURFACE* peSurface;
|
|
|
|
ASSERTGDI(KeGetCurrentIrql() == PASSIVE_LEVEL,
|
|
"DdDxApiOpenSurface: Callable only at passive level (it's not pageable)");
|
|
|
|
hSurface = 0; // Assume failure
|
|
|
|
pDxObjDirectDraw = (DXOBJ*) pOpenSurfaceIn->hDirectDraw;
|
|
|
|
ASSERTGDI((pDxObjDirectDraw != NULL) &&
|
|
(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW),
|
|
"DdDxApiOpenSurface: Invalid hDirectDraw, we're about to crash");
|
|
|
|
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
|
|
|
|
// Among other things, enforce synchronization while we muck around
|
|
// in the DirectDraw object:
|
|
|
|
EDD_DEVLOCK eDevLock(peDxDirectDraw->hdev);
|
|
|
|
if (!peDxDirectDraw->bLost)
|
|
{
|
|
peDirectDrawGlobal = peDxDirectDraw->peDirectDrawGlobal;
|
|
|
|
peSurface = eLockSurface.peLock((HANDLE) pOpenSurfaceIn->dwSurfaceHandle);
|
|
if ((peSurface != NULL) &&
|
|
(peSurface->peDirectDrawGlobal == peDirectDrawGlobal))
|
|
{
|
|
pDxObj = pDdDxObjHandleAllocate(DXT_SURFACE,
|
|
pOpenSurfaceIn->pfnSurfaceClose,
|
|
DDNOTIFY_CLOSESURFACE,
|
|
pOpenSurfaceIn->pContext);
|
|
if (pDxObj != NULL)
|
|
{
|
|
peDxSurface = peSurface->peDxSurface;
|
|
if (peDxSurface != NULL)
|
|
{
|
|
// Just add this object to the list hanging off the
|
|
// surface object:
|
|
|
|
pDxObj->peDxSurface = peDxSurface;
|
|
pDxObj->pDxObj_Next = peDxSurface->pDxObj_List;
|
|
peDxSurface->pDxObj_List = pDxObj;
|
|
|
|
// Success!
|
|
|
|
hSurface = (HANDLE) pDxObj;
|
|
}
|
|
else
|
|
{
|
|
peDxSurface = (EDD_DXSURFACE*) pDdDxObjDataAllocate(
|
|
sizeof(*peDxSurface),
|
|
'sxdG');
|
|
if (peDxSurface)
|
|
{
|
|
RtlZeroMemory(peDxSurface, sizeof(*peDxSurface));
|
|
|
|
pDxObj->peDxSurface = peDxSurface;
|
|
|
|
peSurface->peDxSurface = peDxSurface;
|
|
|
|
peDxSurface->pDxObj_List = pDxObj;
|
|
peDxSurface->peSurface = peSurface;
|
|
peDxSurface->peDxDirectDraw = peDxDirectDraw;
|
|
if( peDirectDrawGlobal->HalInfo.ddCaps.dwCaps2 &
|
|
DDCAPS2_CANBOBINTERLEAVED )
|
|
{
|
|
peDxSurface->flFlags |= DD_DXSURFACE_FLAG_CAN_BOB_INTERLEAVED;
|
|
}
|
|
if( peDirectDrawGlobal->HalInfo.ddCaps.dwCaps2 &
|
|
DDCAPS2_CANBOBNONINTERLEAVED )
|
|
{
|
|
peDxSurface->flFlags |= DD_DXSURFACE_FLAG_CAN_BOB_NONINTERLEAVED;
|
|
}
|
|
|
|
// Success!
|
|
|
|
hSurface = (HANDLE) pDxObj;
|
|
}
|
|
}
|
|
|
|
vDdSynchronizeSurface(peSurface);
|
|
|
|
if (!hSurface)
|
|
{
|
|
vDdDxObjFree(pDxObj);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DdDxApiOpenSurface: Invalid dwSurfaceHandle, failing.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DdDxApiOpenSurface: DirectDraw object lost\n");
|
|
}
|
|
|
|
pOpenSurfaceOut->hSurface = hSurface;
|
|
pOpenSurfaceOut->ddRVal = (hSurface != NULL) ? DD_OK : DDERR_GENERIC;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DdDxApiCloseHandle
|
|
*
|
|
* 14-Apr-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
APIENTRY
|
|
DdDxApiCloseHandle(
|
|
DDCLOSEHANDLE* pCloseHandle,
|
|
DWORD* pdwRet
|
|
)
|
|
{
|
|
DXOBJ* pDxObj = (DXOBJ*) pCloseHandle->hHandle;
|
|
|
|
ASSERTGDI(KeGetCurrentIrql() == PASSIVE_LEVEL,
|
|
"DdDxApiCloseHandle: Callable only at passive level (it's not pageable)");
|
|
ASSERTGDI(pCloseHandle->hHandle != NULL,
|
|
"DdDxApiCloseHandle: Trying to close NULL handle");
|
|
|
|
switch(pDxObj->iDxType)
|
|
{
|
|
case DXT_DIRECTDRAW:
|
|
vDdDxApiFreeDirectDraw(pDxObj, TRUE);
|
|
break;
|
|
|
|
case DXT_VIDEOPORT:
|
|
vDdDxApiFreeVideoPort(pDxObj, FALSE);
|
|
break;
|
|
|
|
case DXT_SURFACE:
|
|
vDdDxApiFreeSurface(pDxObj, FALSE);
|
|
break;
|
|
|
|
case DXT_CAPTURE:
|
|
vDdDxApiFreeCapture(pDxObj, FALSE);
|
|
break;
|
|
|
|
case DXT_INVALID:
|
|
RIP("DdDxApiCloseHandle: Invalid surface. Same handle probably closed twice");
|
|
break;
|
|
|
|
default:
|
|
RIP("DdDxApiCloseHandle: Invalid surface.");
|
|
break;
|
|
}
|
|
|
|
*pdwRet = DD_OK;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DdDxApiOpenCaptureDevice
|
|
*
|
|
* 01-Nov-1997 -by- smac
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
APIENTRY
|
|
DdDxApiOpenCaptureDevice(
|
|
DDOPENVPCAPTUREDEVICEIN* pOpenCaptureDeviceIn,
|
|
DDOPENVPCAPTUREDEVICEOUT* pOpenCaptureDeviceOut
|
|
)
|
|
{
|
|
HANDLE hCaptureDevice;
|
|
DXOBJ* pDxObjDirectDraw;
|
|
DXOBJ* pDxObjVideoPort;
|
|
DXOBJ* pDxObj;
|
|
EDD_DXDIRECTDRAW* peDxDirectDraw;
|
|
EDD_DXVIDEOPORT* peDxVideoPort;
|
|
EDD_DXCAPTURE* peDxCapture;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
DWORD dwRet;
|
|
|
|
ASSERTGDI(KeGetCurrentIrql() == PASSIVE_LEVEL,
|
|
"DdDxApiOpenVideoPort: Callable only at passive level (it's not pageable)");
|
|
|
|
hCaptureDevice = 0; // Assume failure
|
|
|
|
pDxObjDirectDraw = (DXOBJ*) pOpenCaptureDeviceIn->hDirectDraw;
|
|
pDxObjVideoPort = (DXOBJ*) pOpenCaptureDeviceIn->hVideoPort;
|
|
|
|
ASSERTGDI((pDxObjDirectDraw != NULL) &&
|
|
(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW),
|
|
"DdDxApiOpenCaptureDevice: Invalid hDirectDraw, we're about to crash");
|
|
ASSERTGDI((pDxObjVideoPort != NULL) &&
|
|
(pDxObjVideoPort->iDxType == DXT_VIDEOPORT),
|
|
"DdDxApiOpenCaptureDevice: Invalid hVideoPort, we're about to crash");
|
|
|
|
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
|
|
peDxVideoPort = pDxObjVideoPort->peDxVideoPort;
|
|
|
|
ASSERTGDI((pOpenCaptureDeviceIn->dwFlags == DDOPENCAPTURE_VIDEO) ||
|
|
(pOpenCaptureDeviceIn->dwFlags == DDOPENCAPTURE_VBI),
|
|
"DdDxApiOpenCaptureDevice: Invalid flags specified");
|
|
ASSERTGDI((pOpenCaptureDeviceIn->dwCaptureEveryNFields != 0),
|
|
"DdDxApiOpenCaptureDevice: Invalid dwCaptureEveryNFields specified");
|
|
ASSERTGDI((pOpenCaptureDeviceIn->pfnCaptureClose != 0),
|
|
"DdDxApiOpenCaptureDevice: Invalid pfnCaptureClose specified");
|
|
|
|
// Among other things, enforce synchronization while we muck around
|
|
// in the DirectDraw object:
|
|
|
|
EDD_DEVLOCK eDevLock(peDxDirectDraw->hdev);
|
|
|
|
dwRet = DDERR_INVALIDPARAMS;
|
|
if ((!peDxDirectDraw->bLost) &&
|
|
(!peDxVideoPort->bLost))
|
|
{
|
|
// Only do this if the device actually supports capturing
|
|
|
|
dwRet = DDERR_CURRENTLYNOTAVAIL;
|
|
peDirectDrawGlobal = peDxDirectDraw->peDirectDrawGlobal;
|
|
if ((peDirectDrawGlobal->DDKernelCaps.dwCaps &
|
|
(DDKERNELCAPS_CAPTURE_SYSMEM|DDKERNELCAPS_CAPTURE_NONLOCALVIDMEM)) &&
|
|
(peDxDirectDraw->DxApiInterface.DxTransfer != NULL))
|
|
{
|
|
#if 0 // fix bug 169385
|
|
// See capturing target is matched.
|
|
|
|
if (((pOpenCaptureDeviceIn->dwFlags & DDOPENCAPTURE_VBI) &&
|
|
(peDxVideoPort->cAutoflipVbi > 0)) ||
|
|
((pOpenCaptureDeviceIn->dwFlags & DDOPENCAPTURE_VIDEO) &&
|
|
(peDxVideoPort->cAutoflipVideo > 0)))
|
|
{
|
|
#endif
|
|
// Allocate the object. We only allow one handle per object.
|
|
|
|
dwRet = DDERR_OUTOFMEMORY;
|
|
pDxObj = pDdDxObjHandleAllocate(DXT_CAPTURE,
|
|
pOpenCaptureDeviceIn->pfnCaptureClose,
|
|
DDNOTIFY_CLOSECAPTURE,
|
|
pOpenCaptureDeviceIn->pContext);
|
|
if (pDxObj != NULL)
|
|
{
|
|
peDxCapture = (EDD_DXCAPTURE*) pDdDxObjDataAllocate(
|
|
sizeof(*peDxCapture),
|
|
'sxdG');
|
|
if (peDxCapture)
|
|
{
|
|
RtlZeroMemory(peDxCapture, sizeof(*peDxCapture));
|
|
|
|
pDxObj->peDxCapture = peDxCapture;
|
|
|
|
peDxCapture->pDxObj_List = pDxObj;
|
|
peDxCapture->peDxVideoPort = peDxVideoPort;
|
|
peDxCapture->dwStartLine = pOpenCaptureDeviceIn->dwStartLine;
|
|
peDxCapture->dwEndLine = pOpenCaptureDeviceIn->dwEndLine;
|
|
peDxCapture->dwCaptureCountDown = 1;
|
|
peDxCapture->dwCaptureEveryNFields =
|
|
pOpenCaptureDeviceIn->dwCaptureEveryNFields;
|
|
if (pOpenCaptureDeviceIn->dwFlags & DDOPENCAPTURE_VBI )
|
|
{
|
|
peDxCapture->flFlags = DD_DXCAPTURE_FLAG_VBI;
|
|
}
|
|
else
|
|
{
|
|
peDxCapture->flFlags = DD_DXCAPTURE_FLAG_VIDEO;
|
|
}
|
|
|
|
// Now we need to put the capture object into the list
|
|
// of active capture objects, but since this list is
|
|
// walked at DPC time, we need to call DxApi to do this.
|
|
|
|
peDirectDrawGlobal->pfnUpdateCapture( peDxVideoPort,
|
|
peDxCapture, FALSE );
|
|
|
|
// Success!
|
|
|
|
hCaptureDevice = (HANDLE) pDxObj;
|
|
dwRet = DD_OK;
|
|
}
|
|
|
|
if (!hCaptureDevice)
|
|
{
|
|
vDdDxObjFree(pDxObj);
|
|
}
|
|
}
|
|
#if 0 // fix bug 169385
|
|
}
|
|
else
|
|
{
|
|
WARNING("DdDxApiOpenCaptureDevice: VideoPort doesn't have surface requested by driver.\n");
|
|
}
|
|
#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
WARNING("DdDxApiOpenCaptureDevice: Device does not support capture, failing.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DdDxApiOpenCaptureDevice: DirectDraw or VideoPort object is not valid, failing.\n");
|
|
}
|
|
|
|
pOpenCaptureDeviceOut->hCapture = hCaptureDevice;
|
|
pOpenCaptureDeviceOut->ddRVal = dwRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DdDxApiGetKernelCaps
|
|
*
|
|
* 01-Nov-1997 -by- smac
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
APIENTRY
|
|
DdDxApiGetKernelCaps(
|
|
HANDLE hDirectDraw,
|
|
DDGETKERNELCAPSOUT* pGetKernelCaps
|
|
)
|
|
{
|
|
DXOBJ* pDxObjDirectDraw;
|
|
EDD_DXDIRECTDRAW* peDxDirectDraw;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
ASSERTGDI(KeGetCurrentIrql() == PASSIVE_LEVEL,
|
|
"DdDxApiGetKernelCaps: Callable only at passive level (it's not pageable)");
|
|
|
|
pDxObjDirectDraw = (DXOBJ*) hDirectDraw;
|
|
|
|
ASSERTGDI((pDxObjDirectDraw != NULL) &&
|
|
(pDxObjDirectDraw->iDxType == DXT_DIRECTDRAW),
|
|
"DdDxApiGetKernelCaps: Invalid hDirectDraw, we're about to crash");
|
|
|
|
peDxDirectDraw = pDxObjDirectDraw->peDxDirectDraw;
|
|
|
|
// Among other things, enforce synchronization while we muck around
|
|
// in the DirectDraw object:
|
|
|
|
EDD_DEVLOCK eDevLock(peDxDirectDraw->hdev);
|
|
|
|
if (!peDxDirectDraw->bLost)
|
|
{
|
|
peDirectDrawGlobal = peDxDirectDraw->peDirectDrawGlobal;
|
|
|
|
pGetKernelCaps->ddRVal = DD_OK;
|
|
pGetKernelCaps->dwCaps = peDirectDrawGlobal->DDKernelCaps.dwCaps;
|
|
pGetKernelCaps->dwIRQCaps = peDirectDrawGlobal->DDKernelCaps.dwIRQCaps;
|
|
}
|
|
else
|
|
{
|
|
pGetKernelCaps->ddRVal = DXERR_OUTOFCAPS;
|
|
pGetKernelCaps->dwCaps = 0;
|
|
pGetKernelCaps->dwIRQCaps = 0;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DdDxApiLockDevice
|
|
*
|
|
* 05-Jun-1998 -by- agodfrey
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
APIENTRY
|
|
DdDxApiLockDevice(
|
|
HDEV hdev
|
|
)
|
|
{
|
|
DxEngLockHdev(hdev);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DdDxApiUnlockDevice
|
|
*
|
|
* 05-Jun-1998 -by- agodfrey
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
APIENTRY
|
|
DdDxApiUnlockDevice(
|
|
HDEV hdev
|
|
)
|
|
{
|
|
DxEngUnlockHdev(hdev);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDvpCanCreateVideoPort
|
|
*
|
|
* Queries the driver to determine whether it can support a DirectDraw
|
|
* videoPort.
|
|
*
|
|
* 3-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpCanCreateVideoPort(
|
|
HANDLE hDirectDraw,
|
|
PDD_CANCREATEVPORTDATA puCanCreateVPortData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_CANCREATEVPORTDATA CanCreateVideoPort;
|
|
DDVIDEOPORTDESC VideoPortDescription;
|
|
|
|
__try
|
|
{
|
|
CanCreateVideoPort
|
|
= ProbeAndReadStructure(puCanCreateVPortData,
|
|
DD_CANCREATEVPORTDATA);
|
|
|
|
VideoPortDescription
|
|
= ProbeAndReadStructure(CanCreateVideoPort.lpDDVideoPortDesc,
|
|
DDVIDEOPORTDESC);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
CanCreateVideoPort.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
|
|
|
|
// For now, do now enable VPE on Terminal Server due to problems
|
|
// loading DXAPI.SYS into session space vs. non-session space
|
|
|
|
{
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
CanCreateVideoPort.lpDD = peDirectDrawGlobal;
|
|
CanCreateVideoPort.lpDDVideoPortDesc = &VideoPortDescription;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.CanCreateVideoPort))
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
VideoPortCallBacks.CanCreateVideoPort(&CanCreateVideoPort);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpCanCreateSurface: Invalid object\n");
|
|
}
|
|
}
|
|
|
|
// We have to wrap this in another try-except because the user-mode
|
|
// memory containing the input may have been deallocated by now:
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteRVal(&puCanCreateVPortData->ddRVal,
|
|
CanCreateVideoPort.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
return(dwRet);
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* HANDLE DxDvpCreateVideoPort
|
|
*
|
|
* Notifies the HAL after a video port is created.
|
|
*
|
|
* This is an optional call for the driver, but we always have to 'hook'
|
|
* this call from user-mode DirectDraw.
|
|
*
|
|
* Question: A user-mode application could have absolute garbage in
|
|
* lpDDVideoPortDesc and get it by the driver, because the
|
|
* driver would only be monitoring for invalid data in its
|
|
* CanCreateVideoPort call. So should we call the driver's
|
|
* CanCreateVideoPort here in this routine before calling
|
|
* CreateVideoPort?
|
|
*
|
|
* History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HANDLE
|
|
APIENTRY
|
|
DxDvpCreateVideoPort(
|
|
HANDLE hDirectDraw,
|
|
PDD_CREATEVPORTDATA puCreateVPortData
|
|
)
|
|
{
|
|
HANDLE hRet;
|
|
DWORD dwRet;
|
|
DD_CREATEVPORTDATA CreateVPortData;
|
|
DDVIDEOPORTDESC VideoPortDescription;
|
|
BOOL bFirst;
|
|
|
|
__try
|
|
{
|
|
CreateVPortData =
|
|
ProbeAndReadStructure(puCreateVPortData,
|
|
DD_CREATEVPORTDATA);
|
|
|
|
VideoPortDescription
|
|
= ProbeAndReadStructure(CreateVPortData.lpDDVideoPortDesc,
|
|
DDVIDEOPORTDESC);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
hRet = 0;
|
|
CreateVPortData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
|
|
// The two items below where triple bang comments are are somewhat cryptic.
|
|
//
|
|
// 1. Ensure that not more than one VideoPort created
|
|
// 2. Scott allows CanCreateVideoPort and CreateVideoPort to be optional
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
|
|
|
|
// For now, enable VPE on Terminal Server due to conflicts loading in
|
|
// session space vs. non-session sapce.
|
|
|
|
{
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
// Here we do the minimal validations checks to ensure that bad
|
|
// parameters won't crash NT. We're not more strict than
|
|
// checking for stuff that will crash us, as the user-mode part
|
|
// of DirectDraw handles that.
|
|
|
|
if (VideoPortDescription.dwVideoPortID <
|
|
peDirectDrawGlobal->HalInfo.ddCaps.dwMaxVideoPorts)
|
|
{
|
|
|
|
// Check for the case where a video port has been created for
|
|
// VBI or video and we are now creating the other one, in which
|
|
// case we use the existing video port.
|
|
|
|
peVideoPort = peDirectDrawLocal->peVideoPort_DdList;
|
|
while ((peVideoPort != NULL) &&
|
|
(peVideoPort->ddvpDesc.dwVideoPortID != VideoPortDescription.dwVideoPortID))
|
|
{
|
|
peVideoPort = peVideoPort->peVideoPort_DdNext;
|
|
}
|
|
if (peVideoPort != NULL)
|
|
{
|
|
peVideoPort->ddvpDesc = VideoPortDescription;
|
|
CreateVPortData.ddRVal = DD_OK;
|
|
hRet = peVideoPort->hGet();
|
|
}
|
|
else
|
|
{
|
|
peVideoPort = (EDD_VIDEOPORT*) DdHmgAlloc(sizeof(EDD_VIDEOPORT),
|
|
DD_VIDEOPORT_TYPE,
|
|
HMGR_ALLOC_LOCK);
|
|
|
|
if (peVideoPort)
|
|
{
|
|
// Private data:
|
|
|
|
peVideoPort->peDirectDrawGlobal = peDirectDrawGlobal;
|
|
peVideoPort->peDirectDrawLocal = peDirectDrawLocal;
|
|
|
|
// Public data:
|
|
|
|
peVideoPort->lpDD = peDirectDrawGlobal;
|
|
peVideoPort->ddvpDesc = VideoPortDescription;
|
|
|
|
// Hold devlock for driver call and for bDdEnableSoftware
|
|
// Autoflipping.
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
// Add this videoport to the list hanging off the
|
|
// DirectDrawLocal object allocated for this process:
|
|
|
|
bFirst = peDirectDrawLocal->peVideoPort_DdList == NULL;
|
|
peVideoPort->peVideoPort_DdNext
|
|
= peDirectDrawLocal->peVideoPort_DdList;
|
|
peDirectDrawLocal->peVideoPort_DdList
|
|
= peVideoPort;
|
|
|
|
// Now call the driver to create its version:
|
|
|
|
CreateVPortData.lpDD = peDirectDrawGlobal;
|
|
CreateVPortData.lpDDVideoPortDesc = &VideoPortDescription;
|
|
CreateVPortData.lpVideoPort = peVideoPort;
|
|
CreateVPortData.ddRVal = DDERR_GENERIC;
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED; // Call is optional
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.CreateVideoPort))
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
VideoPortCallBacks.CreateVideoPort(&CreateVPortData);
|
|
}
|
|
|
|
if ((dwRet == DDHAL_DRIVER_NOTHANDLED) ||
|
|
(CreateVPortData.ddRVal == DD_OK))
|
|
{
|
|
CreateVPortData.ddRVal = DD_OK;
|
|
peVideoPort->fl |= DD_VIDEOPORT_FLAG_DRIVER_CREATED;
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpCreateVideoPort: Driver failed call\n");
|
|
}
|
|
|
|
if ((CreateVPortData.ddRVal == DD_OK) &&
|
|
(bDdEnableSoftwareAutoflipping(peDirectDrawLocal,
|
|
peVideoPort,
|
|
VideoPortDescription.dwVideoPortID,
|
|
bFirst)))
|
|
{
|
|
// Success!
|
|
|
|
hRet = peVideoPort->hGet();
|
|
|
|
DEC_EXCLUSIVE_REF_CNT( peVideoPort );
|
|
}
|
|
else
|
|
{
|
|
bDdDeleteVideoPortObject(peVideoPort->hGet(), NULL);
|
|
|
|
CreateVPortData.ddRVal = DDERR_GENERIC;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpCreateVideoPort: Bad parameters\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpCreateVideoPort: Invalid object\n");
|
|
}
|
|
}
|
|
|
|
// We have to wrap this in another try-except because the user-mode
|
|
// memory containing the input may have been deallocated by now:
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteRVal(&puCreateVPortData->ddRVal, CreateVPortData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
// Note that the user-mode stub always returns DDHAL_DRIVER_HANDLED
|
|
// to DirectDraw.
|
|
|
|
return(hRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDvpDestroyVideoPort
|
|
*
|
|
* Notifies the HAL when the video port is destroyed.
|
|
*
|
|
* History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpDestroyVideoPort(
|
|
HANDLE hVideoPort,
|
|
PDD_DESTROYVPORTDATA puDestroyVPortData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
|
|
bDdDeleteVideoPortObject(hVideoPort, &dwRet);
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteRVal(&puDestroyVPortData->ddRVal, DD_OK);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDvpFlipVideoPort
|
|
*
|
|
* Performs the physical flip, causing the video port to start writing data
|
|
* to the new surface. This does not affect the actual display of this data.
|
|
*
|
|
* History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpFlipVideoPort(
|
|
HANDLE hVideoPort,
|
|
HANDLE hDDSurfaceCurrent,
|
|
HANDLE hDDSurfaceTarget,
|
|
PDD_FLIPVPORTDATA puFlipVPortData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_FLIPVPORTDATA FlipVPortData;
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
FlipVPortData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_LOCK_VIDEOPORT eLockVideoPort;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
// 1. Make sure they're videoport surfaces, and compatible, not system surfaces?
|
|
// 2. Make sure not software autoflipping?
|
|
|
|
peVideoPort = eLockVideoPort.peLock(hVideoPort);
|
|
if (peVideoPort != NULL)
|
|
{
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
if (peDirectDrawGlobal->VideoPortCallBacks.FlipVideoPort)
|
|
{
|
|
EDD_SURFACE* peSurfaceCurrent;
|
|
EDD_SURFACE* peSurfaceTarget;
|
|
EDD_LOCK_SURFACE eLockSurfaceCurrent;
|
|
EDD_LOCK_SURFACE eLockSurfaceTarget;
|
|
|
|
peSurfaceCurrent = eLockSurfaceCurrent.peLock(hDDSurfaceCurrent);
|
|
peSurfaceTarget = eLockSurfaceTarget.peLock(hDDSurfaceTarget);
|
|
|
|
if ((peSurfaceCurrent != NULL) &&
|
|
(peSurfaceTarget != NULL) &&
|
|
(peSurfaceCurrent->peDirectDrawGlobal == peDirectDrawGlobal) &&
|
|
(peSurfaceCurrent->peDirectDrawLocal
|
|
== peSurfaceTarget->peDirectDrawLocal))
|
|
{
|
|
FlipVPortData.lpDD = peDirectDrawGlobal;
|
|
FlipVPortData.lpVideoPort = peVideoPort;
|
|
FlipVPortData.lpSurfCurr = peSurfaceCurrent;
|
|
FlipVPortData.lpSurfTarg = peSurfaceTarget;
|
|
|
|
{
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.FlipVideoPort))
|
|
{
|
|
dwRet = peDirectDrawGlobal->VideoPortCallBacks.
|
|
FlipVideoPort(&FlipVPortData);
|
|
}
|
|
}
|
|
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(FlipVPortData.ddRVal == DD_OK))
|
|
{
|
|
peVideoPort->lpSurface = peSurfaceTarget;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpFlipVPort: Invalid source or target surface\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpFlipVPort: Driver doesn't hook call\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpFlipVPort: Invalid object\n");
|
|
}
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteRVal(&puFlipVPortData->ddRVal, FlipVPortData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxGetVideoPortBandwidth
|
|
*
|
|
* Informs the client of bandwidth requirements for any specified format,
|
|
* allowing them to better chose a format and to understand its limitations.
|
|
* This information can only be given after the video port object is created
|
|
* because the information in the DDVIDEOPORTDESC structure is required before
|
|
* accurate bandwidth information can be supplied.
|
|
*
|
|
* History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpGetVideoPortBandwidth(
|
|
HANDLE hVideoPort,
|
|
PDD_GETVPORTBANDWIDTHDATA puGetVPortBandwidthData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETVPORTBANDWIDTHDATA GetVPortBandwidthData;
|
|
LPDDPIXELFORMAT pddpfFormat;
|
|
DDPIXELFORMAT ddpfFormat;
|
|
DDVIDEOPORTBANDWIDTH Bandwidth;
|
|
LPDDVIDEOPORTBANDWIDTH puBandwidth;
|
|
|
|
__try
|
|
{
|
|
GetVPortBandwidthData = ProbeAndReadStructure(puGetVPortBandwidthData,
|
|
DD_GETVPORTBANDWIDTHDATA);
|
|
|
|
ddpfFormat = ProbeAndReadStructure(GetVPortBandwidthData.lpddpfFormat,
|
|
DDPIXELFORMAT);
|
|
|
|
puBandwidth = GetVPortBandwidthData.lpBandwidth;
|
|
|
|
Bandwidth = ProbeAndReadStructure(puBandwidth,DDVIDEOPORTBANDWIDTH);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
GetVPortBandwidthData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_LOCK_VIDEOPORT eLockVideoPort;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peVideoPort = eLockVideoPort.peLock(hVideoPort);
|
|
if (peVideoPort != NULL)
|
|
{
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
|
|
if (peDirectDrawGlobal->VideoPortCallBacks.GetVideoPortBandwidth)
|
|
{
|
|
GetVPortBandwidthData.lpDD = peDirectDrawGlobal;
|
|
GetVPortBandwidthData.lpVideoPort = peVideoPort;
|
|
GetVPortBandwidthData.lpBandwidth = &Bandwidth;
|
|
GetVPortBandwidthData.lpddpfFormat = &ddpfFormat;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.GetVideoPortBandwidth))
|
|
{
|
|
dwRet = peDirectDrawGlobal->VideoPortCallBacks.
|
|
GetVideoPortBandwidth(&GetVPortBandwidthData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpGetVPortBandwidthData: Driver doesn't hook call\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpGetVPortBandwidthData: Invalid object\n");
|
|
}
|
|
|
|
// We have to wrap this in another try-except because the user-mode
|
|
// memory containing the input may have been deallocated by now:
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteStructure(puBandwidth, Bandwidth, DDVIDEOPORTBANDWIDTH);
|
|
|
|
ProbeAndWriteRVal(&puGetVPortBandwidthData->ddRVal,
|
|
GetVPortBandwidthData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDvpGetVideoPortField
|
|
*
|
|
* Sets bField to TRUE if the current field is the even field of an
|
|
* interlaced signal. Otherwise, bField is set to FALSE.
|
|
*
|
|
* History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpGetVideoPortField(
|
|
HANDLE hVideoPort,
|
|
PDD_GETVPORTFIELDDATA puGetVPortFieldData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETVPORTFIELDDATA GetVPortFieldData;
|
|
|
|
__try
|
|
{
|
|
GetVPortFieldData = ProbeAndReadStructure(puGetVPortFieldData,
|
|
DD_GETVPORTFIELDDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
GetVPortFieldData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_LOCK_VIDEOPORT eLockVideoPort;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peVideoPort = eLockVideoPort.peLock(hVideoPort);
|
|
if (peVideoPort != NULL)
|
|
{
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
|
|
GetVPortFieldData.lpDD = peDirectDrawGlobal;
|
|
GetVPortFieldData.lpVideoPort = peVideoPort;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.GetVideoPortField))
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
VideoPortCallBacks.GetVideoPortField(&GetVPortFieldData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpCanGetVPortFieldData: Invalid object\n");
|
|
}
|
|
|
|
// We have to wrap this in another try-except because the user-mode
|
|
// memory containing the input may have been deallocated by now:
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteRVal(&puGetVPortFieldData->ddRVal,
|
|
GetVPortFieldData.ddRVal);
|
|
ProbeAndWriteStructure(&puGetVPortFieldData->bField,
|
|
GetVPortFieldData.bField,
|
|
BOOL);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDvpGetVideoPortFlipStatus
|
|
*
|
|
* Returns DDERR_WASSTILLDRAWING if a video VSYNC has not occurred since the
|
|
* flip was performed on the specified surface. This function allows DDRAW.DLL
|
|
* to fail locks on a surface that was recently flipped from so the HAL doesn't
|
|
* have to account for this.
|
|
*
|
|
* History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpGetVideoPortFlipStatus(
|
|
HANDLE hDirectDraw,
|
|
PDD_GETVPORTFLIPSTATUSDATA puGetVPortFlipStatusData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETVPORTFLIPSTATUSDATA GetVPortFlipStatusData;
|
|
|
|
__try
|
|
{
|
|
GetVPortFlipStatusData = ProbeAndReadStructure(puGetVPortFlipStatusData,
|
|
DD_GETVPORTFLIPSTATUSDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
GetVPortFlipStatusData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
GetVPortFlipStatusData.lpDD = peDirectDrawGlobal;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.GetVideoPortFlipStatus))
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
VideoPortCallBacks.GetVideoPortFlipStatus(
|
|
&GetVPortFlipStatusData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpCanGetVPortFlipStatusData: Invalid object\n");
|
|
}
|
|
|
|
// We have to wrap this in another try-except because the user-mode
|
|
// memory containing the input may have been deallocated by now:
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteRVal(&puGetVPortFlipStatusData->ddRVal,
|
|
GetVPortFlipStatusData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDvpGetVideoPortInputFormats
|
|
*
|
|
* Fills in the specified array with all of the formats that the video port
|
|
* can accept and puts that number in dwNumFormats. If lpddpfFormats is NULL,
|
|
* it only fills in dwNumFormats with the number of formats that it can support.
|
|
* This function is needed because the supported formats may vary depending on
|
|
* the electrical connection of the video port.
|
|
*
|
|
* History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpGetVideoPortInputFormats(
|
|
HANDLE hVideoPort,
|
|
PDD_GETVPORTINPUTFORMATDATA puGetVPortInputFormatData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETVPORTINPUTFORMATDATA GetVPortInputFormatData;
|
|
LPDDPIXELFORMAT puFormat;
|
|
ULONG cjFormat;
|
|
HANDLE hSecure;
|
|
|
|
__try
|
|
{
|
|
GetVPortInputFormatData
|
|
= ProbeAndReadStructure(puGetVPortInputFormatData,
|
|
DD_GETVPORTINPUTFORMATDATA);
|
|
|
|
puFormat = GetVPortInputFormatData.lpddpfFormat;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
GetVPortInputFormatData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_LOCK_VIDEOPORT eLockVideoPort;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peVideoPort = eLockVideoPort.peLock(hVideoPort);
|
|
if (peVideoPort != NULL)
|
|
{
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
|
|
GetVPortInputFormatData.lpDD = peDirectDrawGlobal;
|
|
GetVPortInputFormatData.lpVideoPort = peVideoPort;
|
|
GetVPortInputFormatData.lpddpfFormat = NULL;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.GetVideoPortInputFormats))
|
|
{
|
|
dwRet = peDirectDrawGlobal->VideoPortCallBacks.
|
|
GetVideoPortInputFormats(&GetVPortInputFormatData);
|
|
|
|
cjFormat = GetVPortInputFormatData.dwNumFormats
|
|
* sizeof(DDPIXELFORMAT);
|
|
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(GetVPortInputFormatData.ddRVal == DD_OK) &&
|
|
(cjFormat > 0) &&
|
|
(puFormat != NULL) &&
|
|
!BALLOC_OVERFLOW1(GetVPortInputFormatData.dwNumFormats, DDPIXELFORMAT))
|
|
{
|
|
GetVPortInputFormatData.ddRVal = DDERR_GENERIC;
|
|
hSecure = 0;
|
|
|
|
__try
|
|
{
|
|
ProbeForWrite(puFormat, cjFormat, sizeof(UCHAR));
|
|
|
|
hSecure = MmSecureVirtualMemory(puFormat,
|
|
cjFormat,
|
|
PAGE_READWRITE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
if (hSecure)
|
|
{
|
|
GetVPortInputFormatData.lpddpfFormat = puFormat;
|
|
|
|
dwRet = peDirectDrawGlobal->VideoPortCallBacks.
|
|
GetVideoPortInputFormats(&GetVPortInputFormatData);
|
|
|
|
MmUnsecureVirtualMemory(hSecure);
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpGetVideoPortInputFormats: Bad destination buffer\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpGetVPortInputFormatData: Invalid object\n");
|
|
}
|
|
|
|
// We have to wrap this in another try-except because the user-mode
|
|
// memory containing the input may have been deallocated by now:
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteRVal(&puGetVPortInputFormatData->ddRVal,
|
|
GetVPortInputFormatData.ddRVal);
|
|
ProbeAndWriteUlong(&puGetVPortInputFormatData->dwNumFormats,
|
|
GetVPortInputFormatData.dwNumFormats);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDvpGetVideoPortOutputFormats
|
|
*
|
|
* Fills in the specified array with all of the formats that can be written
|
|
* to the frame buffer based on the specified input format and puts that
|
|
* number in dwNumFormats. If lpddpfOutputFormats is NULL, it only fills
|
|
* in dwNumFormats with the number of formats that can be written to the
|
|
* frame buffer.
|
|
*
|
|
* History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpGetVideoPortOutputFormats(
|
|
HANDLE hVideoPort,
|
|
PDD_GETVPORTOUTPUTFORMATDATA puGetVPortOutputFormatData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETVPORTOUTPUTFORMATDATA GetVPortOutputFormatData;
|
|
LPDDPIXELFORMAT puOutputFormats;
|
|
DDPIXELFORMAT ddpfInputFormat;
|
|
ULONG cjFormat;
|
|
HANDLE hSecure;
|
|
|
|
__try
|
|
{
|
|
GetVPortOutputFormatData
|
|
= ProbeAndReadStructure(puGetVPortOutputFormatData,
|
|
DD_GETVPORTOUTPUTFORMATDATA);
|
|
|
|
ddpfInputFormat
|
|
= ProbeAndReadStructure(GetVPortOutputFormatData.lpddpfInputFormat,
|
|
DDPIXELFORMAT);
|
|
|
|
puOutputFormats = GetVPortOutputFormatData.lpddpfOutputFormats;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
GetVPortOutputFormatData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_LOCK_VIDEOPORT eLockVideoPort;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peVideoPort = eLockVideoPort.peLock(hVideoPort);
|
|
if (peVideoPort != NULL)
|
|
{
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
|
|
GetVPortOutputFormatData.lpDD = peDirectDrawGlobal;
|
|
GetVPortOutputFormatData.lpVideoPort = peVideoPort;
|
|
GetVPortOutputFormatData.lpddpfInputFormat = &ddpfInputFormat;
|
|
GetVPortOutputFormatData.lpddpfOutputFormats = NULL;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.GetVideoPortOutputFormats))
|
|
{
|
|
dwRet = peDirectDrawGlobal->VideoPortCallBacks.
|
|
GetVideoPortOutputFormats(&GetVPortOutputFormatData);
|
|
|
|
cjFormat = GetVPortOutputFormatData.dwNumFormats
|
|
* sizeof(DDPIXELFORMAT);
|
|
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(GetVPortOutputFormatData.ddRVal == DD_OK) &&
|
|
(cjFormat > 0) &&
|
|
(puOutputFormats != NULL) &&
|
|
!BALLOC_OVERFLOW1(GetVPortOutputFormatData.dwNumFormats, DDPIXELFORMAT))
|
|
{
|
|
GetVPortOutputFormatData.ddRVal = DDERR_GENERIC;
|
|
hSecure = 0;
|
|
|
|
__try
|
|
{
|
|
ProbeForWrite(puOutputFormats,
|
|
cjFormat,
|
|
sizeof(UCHAR));
|
|
|
|
hSecure = MmSecureVirtualMemory(puOutputFormats,
|
|
cjFormat,
|
|
PAGE_READWRITE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
if (hSecure)
|
|
{
|
|
GetVPortOutputFormatData.lpddpfOutputFormats
|
|
= puOutputFormats;
|
|
|
|
dwRet = peDirectDrawGlobal->VideoPortCallBacks.
|
|
GetVideoPortOutputFormats(&GetVPortOutputFormatData);
|
|
|
|
MmUnsecureVirtualMemory(hSecure);
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpGetVideoPortOutputFormats: Bad destination buffer\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpGetVPortOutputFormatData: Invalid object\n");
|
|
}
|
|
|
|
// We have to wrap this in another try-except because the user-mode
|
|
// memory containing the input may have been deallocated by now:
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteRVal(&puGetVPortOutputFormatData->ddRVal,
|
|
GetVPortOutputFormatData.ddRVal);
|
|
ProbeAndWriteUlong(&puGetVPortOutputFormatData->dwNumFormats,
|
|
GetVPortOutputFormatData.dwNumFormats);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxGetVideoPortLine
|
|
*
|
|
* Returns the current line counter of the video port.
|
|
*
|
|
* This function is only required if the driver sets the DDVPCAPS_READBACKLINE
|
|
* flag.
|
|
*
|
|
* History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpGetVideoPortLine(
|
|
HANDLE hVideoPort,
|
|
PDD_GETVPORTLINEDATA puGetVPortLineData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETVPORTLINEDATA GetVPortLineData;
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
GetVPortLineData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_LOCK_VIDEOPORT eLockVideoPort;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peVideoPort = eLockVideoPort.peLock(hVideoPort);
|
|
if (peVideoPort != NULL)
|
|
{
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
|
|
GetVPortLineData.lpDD = peDirectDrawGlobal;
|
|
GetVPortLineData.lpVideoPort = peVideoPort;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.GetVideoPortLine))
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
VideoPortCallBacks.GetVideoPortLine(&GetVPortLineData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpGetVPortLineData: Invalid object\n");
|
|
}
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteStructure(puGetVPortLineData,
|
|
GetVPortLineData,
|
|
DD_GETVPORTLINEDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxGetVideoPortConnectInfo
|
|
*
|
|
* Fills in the specified array with all of the connection combinations
|
|
* supported by the specified video port and puts that number in dwNumEntries.
|
|
* If lpConnect is NULL, it only fills in dwNumEntries with the number of
|
|
* DDVIDEOPORTCONNECT entries supported.
|
|
*
|
|
* History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpGetVideoPortConnectInfo(
|
|
HANDLE hDirectDraw,
|
|
PDD_GETVPORTCONNECTDATA puGetVPortConnectData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETVPORTCONNECTDATA GetVPortConnectData;
|
|
DDVIDEOPORTCONNECT* puConnect;
|
|
ULONG cjConnect;
|
|
HANDLE hSecure;
|
|
|
|
__try
|
|
{
|
|
GetVPortConnectData = ProbeAndReadStructure(puGetVPortConnectData,
|
|
DD_GETVPORTCONNECTDATA);
|
|
|
|
puConnect = GetVPortConnectData.lpConnect;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
GetVPortConnectData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
GetVPortConnectData.lpDD = peDirectDrawGlobal;
|
|
GetVPortConnectData.lpConnect = NULL;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.GetVideoPortConnectInfo))
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
VideoPortCallBacks.GetVideoPortConnectInfo(
|
|
&GetVPortConnectData);
|
|
|
|
cjConnect = GetVPortConnectData.dwNumEntries
|
|
* sizeof(DDVIDEOPORTCONNECT);
|
|
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(GetVPortConnectData.ddRVal == DD_OK) &&
|
|
(cjConnect > 0) &&
|
|
(puConnect != NULL) &&
|
|
!BALLOC_OVERFLOW1(GetVPortConnectData.dwNumEntries, DDVIDEOPORTCONNECT))
|
|
{
|
|
GetVPortConnectData.ddRVal = DDERR_GENERIC;
|
|
hSecure = 0;
|
|
|
|
__try
|
|
{
|
|
ProbeForWrite(puConnect, cjConnect, sizeof(UCHAR));
|
|
|
|
hSecure = MmSecureVirtualMemory(puConnect,
|
|
cjConnect,
|
|
PAGE_READWRITE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
if (hSecure)
|
|
{
|
|
GetVPortConnectData.lpConnect = puConnect;
|
|
|
|
dwRet = peDirectDrawGlobal->VideoPortCallBacks.
|
|
GetVideoPortConnectInfo(&GetVPortConnectData);
|
|
|
|
MmUnsecureVirtualMemory(hSecure);
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpGetVideoPortConnectInfo: Bad destination buffer\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpGetVPortConnectData: Invalid object\n");
|
|
}
|
|
|
|
// We have to wrap this in another try-except because the user-mode
|
|
// memory containing the input may have been deallocated by now:
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteRVal(&puGetVPortConnectData->ddRVal,
|
|
GetVPortConnectData.ddRVal);
|
|
ProbeAndWriteUlong(&puGetVPortConnectData->dwNumEntries,
|
|
GetVPortConnectData.dwNumEntries);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DxDvpGetVideoSignalStatus
|
|
*
|
|
* If the video port is receiving a good signal, the HAL should set dwStatus
|
|
* to DDVPSQ_SIGNALOK; otherwise, it should set dwStatus to DDVPSQ_NOSIGNAL.
|
|
*
|
|
*History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpGetVideoSignalStatus(
|
|
HANDLE hVideoPort,
|
|
PDD_GETVPORTSIGNALDATA puGetVPortSignalData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETVPORTSIGNALDATA GetVPortSignalData;
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
GetVPortSignalData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_LOCK_VIDEOPORT eLockVideoPort;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peVideoPort = eLockVideoPort.peLock(hVideoPort);
|
|
if (peVideoPort != NULL)
|
|
{
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
|
|
GetVPortSignalData.lpDD = peDirectDrawGlobal;
|
|
GetVPortSignalData.lpVideoPort = peVideoPort;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.GetVideoSignalStatus))
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
VideoPortCallBacks.GetVideoSignalStatus(&GetVPortSignalData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpGetVPortSignalData: Invalid object\n");
|
|
}
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteStructure(puGetVPortSignalData,
|
|
GetVPortSignalData,
|
|
DD_GETVPORTSIGNALDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDvpUpdateVideoPort
|
|
*
|
|
* Starts, stops, and changes the video port. dwFlags can contain either
|
|
* DDRAWI_VPORTSTART, DDRAWI_VPORTSTOP, or DDRAWI_VPORTUPDATE. To accommodate
|
|
* auto-flipping, lplpDDSurface and lplpDDVBISurface point to an array of
|
|
* surface structures rather than to a single structure. If autoflipping is
|
|
* requested, the dwNumAutoflip field contains the number of surfaces in the
|
|
* list.
|
|
*
|
|
* History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpUpdateVideoPort(
|
|
HANDLE hVideoPort,
|
|
HANDLE* phSurfaceVideo,
|
|
HANDLE* phSurfaceVbi,
|
|
PDD_UPDATEVPORTDATA puUpdateVPortData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_UPDATEVPORTDATA UpdateVPortData;
|
|
DDVIDEOPORTINFO VideoPortInfo;
|
|
DDPIXELFORMAT ddpfInputFormat;
|
|
DDPIXELFORMAT ddpfVBIInputFormat;
|
|
DDPIXELFORMAT ddpfVBIOutputFormat;
|
|
HANDLE ahSurfaceVideo[MAX_AUTOFLIP_BUFFERS];
|
|
HANDLE ahSurfaceVbi[MAX_AUTOFLIP_BUFFERS];
|
|
EDD_SURFACE* apeSurfaceVideo[MAX_AUTOFLIP_BUFFERS];
|
|
EDD_SURFACE* apeSurfaceVbi[MAX_AUTOFLIP_BUFFERS];
|
|
DD_SURFACE_INT* apDDSurfaceVideo[MAX_AUTOFLIP_BUFFERS];
|
|
DD_SURFACE_INT* apDDSurfaceVbi[MAX_AUTOFLIP_BUFFERS];
|
|
ULONG cAutoflipVideo;
|
|
ULONG cAutoflipVbi;
|
|
EDD_DXVIDEOPORT* peDxVideoPort;
|
|
|
|
__try
|
|
{
|
|
UpdateVPortData = ProbeAndReadStructure(puUpdateVPortData,
|
|
DD_UPDATEVPORTDATA);
|
|
|
|
// Handle VideoPortInfo structure:
|
|
|
|
if (UpdateVPortData.dwFlags != DDRAWI_VPORTSTOP)
|
|
{
|
|
VideoPortInfo = ProbeAndReadStructure(UpdateVPortData.lpVideoInfo,
|
|
DDVIDEOPORTINFO);
|
|
|
|
if (VideoPortInfo.lpddpfInputFormat != NULL)
|
|
{
|
|
ddpfInputFormat
|
|
= ProbeAndReadStructure(VideoPortInfo.lpddpfInputFormat,
|
|
DDPIXELFORMAT);
|
|
|
|
VideoPortInfo.lpddpfInputFormat = &ddpfInputFormat;
|
|
}
|
|
if (VideoPortInfo.dwVBIHeight > 0)
|
|
{
|
|
if (VideoPortInfo.lpddpfVBIInputFormat != NULL)
|
|
{
|
|
ddpfVBIInputFormat
|
|
= ProbeAndReadStructure(VideoPortInfo.lpddpfVBIInputFormat,
|
|
DDPIXELFORMAT);
|
|
|
|
VideoPortInfo.lpddpfVBIInputFormat = &ddpfVBIInputFormat;
|
|
}
|
|
if (VideoPortInfo.lpddpfVBIOutputFormat != NULL)
|
|
{
|
|
ddpfVBIOutputFormat
|
|
= ProbeAndReadStructure(VideoPortInfo.lpddpfVBIOutputFormat,
|
|
DDPIXELFORMAT);
|
|
|
|
VideoPortInfo.lpddpfVBIOutputFormat = &ddpfVBIOutputFormat;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VideoPortInfo.lpddpfVBIInputFormat = NULL;
|
|
VideoPortInfo.lpddpfVBIOutputFormat = NULL;
|
|
}
|
|
}
|
|
|
|
// Handle arrays of surfaces:
|
|
|
|
cAutoflipVbi = 0;
|
|
cAutoflipVideo = 0;
|
|
|
|
if (UpdateVPortData.dwFlags != DDRAWI_VPORTSTOP)
|
|
{
|
|
cAutoflipVideo = min(UpdateVPortData.dwNumAutoflip, MAX_AUTOFLIP_BUFFERS);
|
|
if ((cAutoflipVideo == 0) && (UpdateVPortData.lplpDDSurface != NULL))
|
|
{
|
|
cAutoflipVideo = 1;
|
|
}
|
|
|
|
cAutoflipVbi = min(UpdateVPortData.dwNumVBIAutoflip, MAX_AUTOFLIP_BUFFERS);
|
|
if ((cAutoflipVbi == 0) && (UpdateVPortData.lplpDDVBISurface != NULL))
|
|
{
|
|
cAutoflipVbi = 1;
|
|
}
|
|
}
|
|
if (cAutoflipVideo)
|
|
{
|
|
ProbeForRead(phSurfaceVideo,
|
|
cAutoflipVideo * sizeof(HANDLE),
|
|
sizeof(HANDLE));
|
|
RtlCopyMemory(ahSurfaceVideo,
|
|
phSurfaceVideo,
|
|
cAutoflipVideo * sizeof(HANDLE));
|
|
}
|
|
if (cAutoflipVbi)
|
|
{
|
|
ProbeForRead(phSurfaceVbi,
|
|
cAutoflipVbi * sizeof(HANDLE),
|
|
sizeof(HANDLE));
|
|
RtlCopyMemory(ahSurfaceVbi,
|
|
phSurfaceVbi,
|
|
cAutoflipVbi * sizeof(HANDLE));
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
UpdateVPortData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_LOCK_VIDEOPORT eLockVideoPort;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
ULONG i;
|
|
EDD_SURFACE* peSurface;
|
|
|
|
BOOL bUpdateOK = TRUE;
|
|
|
|
peVideoPort = eLockVideoPort.peLock(hVideoPort);
|
|
if (peVideoPort != NULL)
|
|
{
|
|
peDxVideoPort = peVideoPort->peDxVideoPort;
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
|
|
// Lock all the surfaces. Note that bDdUpdateLinksAndSynchronize
|
|
// will check for failure of DdHmgLock (the pointer will be NULL):
|
|
|
|
for (i = 0; i < cAutoflipVideo; i++)
|
|
{
|
|
apeSurfaceVideo[i] = (EDD_SURFACE*)
|
|
DdHmgLock((HDD_OBJ) ahSurfaceVideo[i], DD_SURFACE_TYPE, FALSE);
|
|
}
|
|
for (i = 0; i < cAutoflipVbi; i++)
|
|
{
|
|
apeSurfaceVbi[i] = (EDD_SURFACE*)
|
|
DdHmgLock((HDD_OBJ) ahSurfaceVbi[i], DD_SURFACE_TYPE, FALSE);
|
|
}
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.UpdateVideoPort) &&
|
|
(bUpdateOK = bDdUpdateLinksAndSynchronize(
|
|
peVideoPort,
|
|
TRUE, // Update video
|
|
apeSurfaceVideo,
|
|
cAutoflipVideo,
|
|
TRUE, // Update VBI
|
|
apeSurfaceVbi,
|
|
cAutoflipVbi)))
|
|
{
|
|
UpdateVPortData.lpDD = peDirectDrawGlobal;
|
|
UpdateVPortData.lpVideoPort = peVideoPort;
|
|
UpdateVPortData.lplpDDSurface = NULL;
|
|
UpdateVPortData.lplpDDVBISurface = NULL;
|
|
UpdateVPortData.dwNumAutoflip = cAutoflipVideo;
|
|
UpdateVPortData.dwNumVBIAutoflip = cAutoflipVbi;
|
|
UpdateVPortData.lpVideoInfo
|
|
= (UpdateVPortData.dwFlags == DDRAWI_VPORTSTOP)
|
|
? NULL
|
|
: &VideoPortInfo;
|
|
|
|
if (cAutoflipVideo != 0)
|
|
{
|
|
for (i = 0; i < cAutoflipVideo; i++)
|
|
{
|
|
apDDSurfaceVideo[i] = apeSurfaceVideo[i];
|
|
}
|
|
UpdateVPortData.lplpDDSurface = apDDSurfaceVideo;
|
|
}
|
|
if (cAutoflipVbi != 0)
|
|
{
|
|
for (i = 0; i < cAutoflipVbi; i++)
|
|
{
|
|
apDDSurfaceVbi[i] = apeSurfaceVbi[i];
|
|
}
|
|
UpdateVPortData.lplpDDVBISurface = apDDSurfaceVbi;
|
|
}
|
|
|
|
// Turn off software autoflipping if necessary:
|
|
|
|
if (UpdateVPortData.dwFlags == DDRAWI_VPORTSTOP)
|
|
{
|
|
peDxVideoPort->bSoftwareAutoflip = FALSE;
|
|
peDxVideoPort->flFlags &= ~(DD_DXVIDEOPORT_FLAG_AUTOFLIP|DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI);
|
|
|
|
// Disable the video port VSYNC IRQ now
|
|
|
|
if( peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_ON )
|
|
{
|
|
peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_ON;
|
|
peDirectDrawGlobal->pfnEnableIRQ(peDxVideoPort, FALSE );
|
|
}
|
|
}
|
|
|
|
// We don't allow switching back to hardware once software
|
|
// autoflipping has started (for various reasons, among
|
|
// them being how do we synchronize -- the hardware would
|
|
// start autoflipping before we could turn off the software
|
|
// autoflipping).
|
|
|
|
if (peDxVideoPort->bSoftwareAutoflip)
|
|
{
|
|
VideoPortInfo.dwVPFlags &= ~DDVP_AUTOFLIP;
|
|
}
|
|
|
|
// Make the HAL call:
|
|
|
|
dwRet = peDirectDrawGlobal->
|
|
VideoPortCallBacks.UpdateVideoPort(&UpdateVPortData);
|
|
|
|
// If we failed due to a request for hardware autoflipping,
|
|
// try again with software autoflipping.
|
|
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(UpdateVPortData.ddRVal != DD_OK) &&
|
|
(peDirectDrawGlobal->DDKernelCaps.dwCaps & DDKERNELCAPS_AUTOFLIP))
|
|
{
|
|
VideoPortInfo.dwVPFlags &= ~DDVP_AUTOFLIP;
|
|
|
|
dwRet = peDirectDrawGlobal->
|
|
VideoPortCallBacks.UpdateVideoPort(&UpdateVPortData);
|
|
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(UpdateVPortData.ddRVal == DD_OK))
|
|
{
|
|
KdPrint(("DxDvpUpdateVideoPort: Software autoflipping\n"));
|
|
|
|
peDxVideoPort->bSoftwareAutoflip = TRUE;
|
|
UpdateVPortData.ddRVal = DD_OK;
|
|
}
|
|
}
|
|
|
|
if ((UpdateVPortData.ddRVal == DD_OK) &&
|
|
peDxVideoPort->bSoftwareAutoflip)
|
|
{
|
|
if( cAutoflipVideo > 0 )
|
|
{
|
|
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_AUTOFLIP;
|
|
}
|
|
if( cAutoflipVbi > 0 )
|
|
{
|
|
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bUpdateOK)
|
|
{
|
|
WARNING("DxDvpUpdateVideoPort: failed on bDdUpdateLinksAndSynchronize");
|
|
}
|
|
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(UpdateVPortData.ddRVal == DD_OK))
|
|
{
|
|
// Success!
|
|
|
|
peVideoPort->dwNumAutoflip = cAutoflipVideo;
|
|
peVideoPort->dwNumVBIAutoflip = cAutoflipVbi;
|
|
if (UpdateVPortData.dwFlags != DDRAWI_VPORTSTOP)
|
|
{
|
|
peVideoPort->ddvpInfo = VideoPortInfo;
|
|
|
|
if (VideoPortInfo.lpddpfInputFormat != NULL)
|
|
{
|
|
peVideoPort->ddvpInfo.lpddpfInputFormat
|
|
= &peVideoPort->ddpfInputFormat;
|
|
|
|
peVideoPort->ddpfInputFormat = ddpfInputFormat;
|
|
}
|
|
else
|
|
{
|
|
peVideoPort->ddvpInfo.lpddpfInputFormat = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update various DXAPI state to reflect the changes:
|
|
|
|
vDdSynchronizeVideoPort(peVideoPort);
|
|
|
|
// If it wasn't previously on, enable the video port VSYNC IRQ now
|
|
//
|
|
// if bDdUpdateLinksAndSynchronize failed, don't enable.
|
|
|
|
if( (bUpdateOK) &&
|
|
(UpdateVPortData.dwFlags != DDRAWI_VPORTSTOP) &&
|
|
!(peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_ON) )
|
|
{
|
|
peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_ON;
|
|
peDirectDrawGlobal->pfnEnableIRQ(peDxVideoPort, TRUE );
|
|
}
|
|
|
|
// Unlock the memory that I've locked
|
|
|
|
for (i = 0; i < cAutoflipVideo; i++)
|
|
{
|
|
if( apeSurfaceVideo[i] != NULL )
|
|
DEC_EXCLUSIVE_REF_CNT( apeSurfaceVideo[i] );
|
|
}
|
|
for (i = 0; i < cAutoflipVbi; i++)
|
|
{
|
|
if( apeSurfaceVbi[i] != NULL )
|
|
DEC_EXCLUSIVE_REF_CNT( apeSurfaceVbi[i] );
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpUpdateVPortData: Invalid object\n");
|
|
}
|
|
|
|
// We have to wrap this in another try-except because the user-mode
|
|
// memory containing the input may have been deallocated by now:
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteRVal(&puUpdateVPortData->ddRVal, UpdateVPortData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDvpWaitForVideoPortSync
|
|
*
|
|
* Returns at the beginning or end of either the video VSYNC or the specified
|
|
* line. If the sync does not occur before the number of milliseconds
|
|
* specified in dwTimeOut has elapsed, the HAL should return
|
|
* DDERR_VIDEONOTACTIVE.
|
|
*
|
|
* History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpWaitForVideoPortSync(
|
|
HANDLE hVideoPort,
|
|
PDD_WAITFORVPORTSYNCDATA puWaitForVPortSyncData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_WAITFORVPORTSYNCDATA WaitForVPortSyncData;
|
|
|
|
__try
|
|
{
|
|
WaitForVPortSyncData = ProbeAndReadStructure(puWaitForVPortSyncData,
|
|
DD_WAITFORVPORTSYNCDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
WaitForVPortSyncData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_LOCK_VIDEOPORT eLockVideoPort;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peVideoPort = eLockVideoPort.peLock(hVideoPort);
|
|
if (peVideoPort != NULL)
|
|
{
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
|
|
WaitForVPortSyncData.lpDD = peDirectDrawGlobal;
|
|
WaitForVPortSyncData.lpVideoPort = peVideoPort;
|
|
|
|
// Cap the number of milliseconds to wait to something reasonable:
|
|
|
|
if (WaitForVPortSyncData.dwTimeOut
|
|
> 6 * peVideoPort->ddvpDesc.dwMicrosecondsPerField)
|
|
{
|
|
WaitForVPortSyncData.dwTimeOut
|
|
= 6 * peVideoPort->ddvpDesc.dwMicrosecondsPerField;
|
|
}
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.WaitForVideoPortSync))
|
|
{
|
|
dwRet = peDirectDrawGlobal->VideoPortCallBacks.
|
|
WaitForVideoPortSync(&WaitForVPortSyncData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpWaitForVPortSyncData: Invalid object\n");
|
|
}
|
|
|
|
// We have to wrap this in another try-except because the user-mode
|
|
// memory containing the input may have been deallocated by now:
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteRVal(&puWaitForVPortSyncData->ddRVal,
|
|
WaitForVPortSyncData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDvpColorControl
|
|
*
|
|
* Gets or sets the current color controls associated with the video port.
|
|
*
|
|
* History:
|
|
* 2-Oct-1996 -by- Lingyun Wang [lingyunw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpColorControl(
|
|
HANDLE hVideoPort,
|
|
PDD_VPORTCOLORDATA puVPortColorData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_VPORTCOLORDATA VPortColorData;
|
|
DDCOLORCONTROL ColorData;
|
|
|
|
__try
|
|
{
|
|
VPortColorData = ProbeAndReadStructure(puVPortColorData,
|
|
DD_VPORTCOLORDATA);
|
|
|
|
ColorData = ProbeAndReadStructure(VPortColorData.lpColorData,
|
|
DDCOLORCONTROL);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
VPortColorData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_LOCK_VIDEOPORT eLockVideoPort;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peVideoPort = eLockVideoPort.peLock(hVideoPort);
|
|
if (peVideoPort != NULL)
|
|
{
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
|
|
VPortColorData.lpDD = peDirectDrawGlobal;
|
|
VPortColorData.lpVideoPort = peVideoPort;
|
|
VPortColorData.lpColorData = &ColorData;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->VideoPortCallBacks.ColorControl))
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
VideoPortCallBacks.ColorControl(&VPortColorData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDvpColorControl: Invalid object\n");
|
|
}
|
|
|
|
// We have to wrap this in another try-except because the user-mode
|
|
// memory containing the input may have been deallocated by now:
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteRVal(&puVPortColorData->ddRVal, VPortColorData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDvpAcquireNotification
|
|
*
|
|
* Sets up the user mode notification of video port vsyncs.
|
|
*
|
|
* History:
|
|
* 10-Oct-2000 -Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpAcquireNotification(
|
|
HANDLE hVideoPort,
|
|
HANDLE * phEvent,
|
|
LPDDVIDEOPORTNOTIFY pNotify
|
|
)
|
|
{
|
|
PKEVENT pEvent = NULL;
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_LOCK_VIDEOPORT eLockVideoPort;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
PMDL mdl;
|
|
LPDDVIDEOPORTNOTIFY pLockedBuffer;
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteHandle(phEvent, NULL);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return DDHAL_DRIVER_NOTHANDLED;
|
|
}
|
|
|
|
// First check the caps to see if this device even supports a vport IRQ
|
|
|
|
peVideoPort = eLockVideoPort.peLock(hVideoPort);
|
|
if ((peVideoPort != NULL) &&
|
|
(peVideoPort->peDxVideoPort->pNotifyEvent == NULL))
|
|
{
|
|
peDirectDrawGlobal = peVideoPort->peDirectDrawGlobal;
|
|
if (peDirectDrawGlobal->DDKernelCaps.dwIRQCaps & DDIRQ_VPORT0_VSYNC )
|
|
{
|
|
// Now setup the buffer so it can be accessed at DPC level
|
|
mdl = IoAllocateMdl(pNotify,
|
|
sizeof(DDVIDEOPORTNOTIFY),
|
|
FALSE,
|
|
FALSE,
|
|
NULL);
|
|
if (mdl != NULL)
|
|
{
|
|
__try
|
|
{
|
|
MmProbeAndLockPages (mdl,
|
|
KernelMode,
|
|
IoWriteAccess);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
IoFreeMdl (mdl);
|
|
mdl = NULL;
|
|
}
|
|
}
|
|
|
|
if (mdl != NULL)
|
|
{
|
|
pLockedBuffer = (LPDDVIDEOPORTNOTIFY)
|
|
MmGetSystemAddressForMdlSafe (mdl,
|
|
NormalPagePriority);
|
|
if (pLockedBuffer == NULL)
|
|
{
|
|
MmUnlockPages (mdl);
|
|
IoFreeMdl (mdl);
|
|
}
|
|
else
|
|
{
|
|
// Now set up the event that we trigger
|
|
|
|
HANDLE h = NULL;
|
|
|
|
ZwCreateEvent( &h,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
SynchronizationEvent,
|
|
FALSE );
|
|
|
|
if (h != NULL)
|
|
{
|
|
(VOID) ObReferenceObjectByHandle( h,
|
|
0,
|
|
0,
|
|
KernelMode,
|
|
(PVOID *) &pEvent,
|
|
NULL );
|
|
}
|
|
|
|
if (pEvent != NULL)
|
|
{
|
|
ObDereferenceObject(pEvent);
|
|
peVideoPort->peDxVideoPort->pNotifyBuffer = pLockedBuffer;
|
|
peVideoPort->peDxVideoPort->pNotifyMdl = mdl;
|
|
peVideoPort->peDxVideoPort->pNotifyEvent = pEvent;
|
|
peVideoPort->peDxVideoPort->pNotifyEventHandle = h;
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteHandle(phEvent, h);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MmUnlockPages (mdl);
|
|
IoFreeMdl (mdl);
|
|
}
|
|
}
|
|
// force software autoflipping
|
|
peVideoPort->peDxVideoPort->bSoftwareAutoflip = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDvpReleaseNotification
|
|
*
|
|
* Stops up the user mode notification of video port vsyncs.
|
|
*
|
|
* History:
|
|
* 10-Oct-2000 -Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDvpReleaseNotification(
|
|
HANDLE hVideoPort,
|
|
HANDLE pEvent
|
|
)
|
|
{
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_LOCK_VIDEOPORT eLockVideoPort;
|
|
|
|
peVideoPort = eLockVideoPort.peLock(hVideoPort);
|
|
if ((peVideoPort != NULL) &&
|
|
(peVideoPort->peDxVideoPort->pNotifyEventHandle == pEvent) &&
|
|
(pEvent != NULL))
|
|
{
|
|
PKEVENT pTemp = NULL;
|
|
NTSTATUS Status;
|
|
|
|
peVideoPort->peDxVideoPort->pNotifyEvent = NULL;
|
|
peVideoPort->peDxVideoPort->pNotifyEventHandle = NULL;
|
|
|
|
// Make sure that the handle hasn't been freed by the OS already
|
|
Status = ObReferenceObjectByHandle( pEvent,
|
|
0,
|
|
0,
|
|
KernelMode,
|
|
(PVOID *) &pTemp,
|
|
NULL );
|
|
if ((pTemp != NULL) && (Status != STATUS_INVALID_HANDLE))
|
|
{
|
|
ObDereferenceObject(pTemp);
|
|
ZwClose (pEvent);
|
|
}
|
|
|
|
peVideoPort->peDxVideoPort->pNotifyBuffer = NULL;
|
|
if (peVideoPort->peDxVideoPort->pNotifyMdl != NULL)
|
|
{
|
|
MmUnlockPages (peVideoPort->peDxVideoPort->pNotifyMdl);
|
|
IoFreeMdl (peVideoPort->peDxVideoPort->pNotifyMdl);
|
|
peVideoPort->peDxVideoPort->pNotifyMdl = NULL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|