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.
13680 lines
480 KiB
13680 lines
480 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: ddraw.cxx
|
|
*
|
|
* Contains all of GDI's private DirectDraw APIs.
|
|
*
|
|
* Created: 3-Dec-1995
|
|
* Author: J. Andrew Goossen [andrewgo]
|
|
*
|
|
* Copyright (c) 1995-1999 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
|
|
#if 0
|
|
#define DBG_DDKHEAP
|
|
#define DDKHEAP(Args) KdPrint(Args)
|
|
#else
|
|
#define DDKHEAP(Args)
|
|
#endif
|
|
|
|
#if 0
|
|
#define DBG_DDKSURF
|
|
#define DDKSURF(Args) KdPrint(Args)
|
|
#else
|
|
#define DDKSURF(Args)
|
|
#endif
|
|
|
|
|
|
// Several AGP routines take an hdev that is some cookie useful in
|
|
// AGP operations. On NT, it's a pointer to the EDD_DIRECTDRAW_GLOBAL.
|
|
// This macro is largely just a marker in case it changes in the
|
|
// future.
|
|
|
|
#define AGP_HDEV(peDirectDrawGlobal) ((HANDLE)peDirectDrawGlobal)
|
|
|
|
// This variable is kept for stress debugging purposes. When a mode change
|
|
// or desktop change is pending and an application has outstanding locks
|
|
// on the frame buffer, we will by default wait up to 7 seconds for the
|
|
// application to release its locks, before we will unmap the view anyway.
|
|
// 'gfpUnmap' will be user-mode address of the unmapped frame buffer, which
|
|
// will be useful for determining in stress whether an application had its
|
|
// frame buffer access rescinded, or whether it was using a completely bogus
|
|
// frame buffer pointer to begin with:
|
|
|
|
FLATPTR gfpUnmap = 0;
|
|
|
|
// The following global variables are kept only for debugging purposes, to
|
|
// aid in tracking DC drawing to surfaces that have been lost:
|
|
|
|
HDC ghdcGetDC;
|
|
HDC ghdcCantLose;
|
|
|
|
#ifdef DX_REDIRECTION
|
|
|
|
// The following global variable is kept the boolean value if system are in
|
|
// redirection mode or not.
|
|
//
|
|
// If system is in redirection mode, we disable ...
|
|
//
|
|
// + Overlay.
|
|
// + Primary surface lock (LATER).
|
|
//
|
|
// !!! Currently this is 'per system' status, so that we can have global variable
|
|
// !!! simply here, but it could be 'per process' or 'per hWnd' in later version.
|
|
// !!! (it's up to how Window manager manage its status)
|
|
|
|
BOOL gbDxRedirection = FALSE;
|
|
|
|
#endif // DX_REDIRECTION
|
|
|
|
|
|
#if DBG
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdAssertDevlock
|
|
*
|
|
* Debug code for verifying that the devlock is currently held.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdAssertShareDevlock()
|
|
{
|
|
#if 0 // TODO: DBG - IsSem...
|
|
ASSERTGDI(GreIsSemaphoreOwnedByCurrentThread(ghsemShareDevLock),
|
|
"DD_ASSERTSHAREDEVLOCK failed");
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
vDdAssertDevlock(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
|
|
)
|
|
{
|
|
ASSERTGDI(DxEngIsHdevLockedByCurrentThread(peDirectDrawGlobal->hdev),
|
|
"DD_ASSERTDEVLOCK failed because Devlock is not held");
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdAssertNoDevlock
|
|
*
|
|
* Debug code for verifying that the devlock is currently not held.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdAssertNoDevlock(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
|
|
)
|
|
{
|
|
ASSERTGDI(!DxEngIsHdevLockedByCurrentThread(peDirectDrawGlobal->hdev),
|
|
"DD_ASSERTNODEVLOCK failed because Devlock held but shouldn't be!");
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdIntersect
|
|
*
|
|
* Ubiquitous lower-right exclusive intersection detection.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
inline
|
|
BOOL
|
|
bDdIntersect(
|
|
RECTL* pA,
|
|
RECTL* pB
|
|
)
|
|
{
|
|
return((pA->left < pB->right) &&
|
|
(pA->top < pB->bottom) &&
|
|
(pA->right > pB->left) &&
|
|
(pA->bottom > pB->top));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdValidateDriverData
|
|
*
|
|
* Performs some parameter validation on the info DirectDraw info returned
|
|
* from the driver.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdValidateDriverData(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
|
|
)
|
|
{
|
|
BOOL b;
|
|
DDNTCORECAPS* pCaps;
|
|
|
|
b = TRUE;
|
|
|
|
if ((peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount != 8) &&
|
|
(peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount != 16) &&
|
|
(peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount != 24) &&
|
|
(peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount != 32))
|
|
{
|
|
RIP("HalInfo.vmiData.ddpfDisplay.dwRGBBitCount not 8, 16, 24 or 32");
|
|
b = FALSE;
|
|
}
|
|
|
|
if (peDirectDrawGlobal->HalInfo.vmiData.lDisplayPitch == 0)
|
|
{
|
|
RIP("HalInfo.vmiData.lDisplayPitch is 0");
|
|
b = FALSE;
|
|
}
|
|
|
|
pCaps = &peDirectDrawGlobal->HalInfo.ddCaps;
|
|
|
|
// Check to see if 'Blt' must be hooked:
|
|
|
|
if (pCaps->dwCaps & (DDCAPS_BLT
|
|
| DDCAPS_BLTCOLORFILL
|
|
| DDCAPS_COLORKEY))
|
|
{
|
|
if (!(peDirectDrawGlobal->SurfaceCallBacks.dwFlags & DDHAL_SURFCB32_BLT) ||
|
|
(peDirectDrawGlobal->SurfaceCallBacks.Blt == NULL))
|
|
{
|
|
RIP("HalInfo.ddCaps.dwCaps indicate driver must hook Blt\n");
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
// We only permit a subset of the DirectDraw capabilities to be hooked
|
|
// by the driver, because the kernel-mode code paths for any other
|
|
// capabilities have not been tested:
|
|
|
|
if (pCaps->dwCaps & (DDCAPS_GDI
|
|
| DDCAPS_PALETTE
|
|
| DDCAPS_ZOVERLAYS
|
|
| DDCAPS_BANKSWITCHED))
|
|
{
|
|
RIP("HalInfo.ddCaps.dwCaps has capabilities set that aren't supported by NT\n");
|
|
b = FALSE;
|
|
}
|
|
|
|
if (pCaps->dwCaps2 & (DDCAPS2_CERTIFIED))
|
|
{
|
|
RIP("HalInfo.ddCaps.dwCaps2 has capabilities set that aren't supported by NT\n");
|
|
b = FALSE;
|
|
}
|
|
|
|
if (pCaps->ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY
|
|
| DDSCAPS_WRITEONLY
|
|
| DDSCAPS_OWNDC
|
|
| DDSCAPS_MODEX))
|
|
{
|
|
RIP("HalInfo.ddCaps.ddsCaps.dwCaps has capabilities set that aren't supported by NT\n");
|
|
b = FALSE;
|
|
}
|
|
|
|
if (pCaps->dwFXCaps & ( DDFXCAPS_BLTROTATION
|
|
| DDFXCAPS_BLTROTATION90))
|
|
{
|
|
RIP("HalInfo.ddCaps.dwFXCaps has capabilities set that aren't supported by NT\n");
|
|
b = FALSE;
|
|
}
|
|
|
|
/*
|
|
* WINBUG #55100 2-1-2000 bhouse Alpha restrictions need to be revisited when AlphaBlt DDI is enabled.
|
|
* We used to check and fail on the presence of either of the following bits:
|
|
* DDFXALPHACAPS_BLTALPHASURFACES 0x00000008l
|
|
* DDFXALPHACAPS_OVERLAYALPHASURFACES 0x00000100l
|
|
*/
|
|
|
|
if (pCaps->dwPalCaps != 0)
|
|
{
|
|
RIP("HalInfo.ddCaps.dwPalCaps has capabilities set that aren't supported by NT\n");
|
|
b = FALSE;
|
|
}
|
|
|
|
// GDI will handle the emulation of system-memory to video-memory blts.
|
|
// Page-locking from user-mode is not allowed on NT, so
|
|
// DDSCAPS2_NOPAGELOCKEDREQUIRED should always be set:
|
|
|
|
if (!(pCaps->dwCaps & DDCAPS_CANBLTSYSMEM) &&
|
|
(peDirectDrawGlobal->SurfaceCallBacks.dwFlags & DDHAL_SURFCB32_BLT) &&
|
|
(peDirectDrawGlobal->SurfaceCallBacks.Blt != NULL))
|
|
{
|
|
peDirectDrawGlobal->flDriver |= DD_DRIVER_FLAG_EMULATE_SYSTEM_TO_VIDEO;
|
|
|
|
pCaps->dwCaps2 |= DDCAPS2_NOPAGELOCKREQUIRED;
|
|
}
|
|
|
|
return(b);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdGetDriverInfo
|
|
*
|
|
* Assumes devlock already held.
|
|
*
|
|
* In case the driver partially filled in the structure before it decided
|
|
* to fail, we always zero the buffer in the event of failure.
|
|
*
|
|
* 16-Feb-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdGetDriverInfo(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
const GUID* pGuid,
|
|
VOID* pvBuffer,
|
|
ULONG cjSize,
|
|
ULONG* pjSizeReturned
|
|
)
|
|
{
|
|
PDD_GETDRIVERINFO pfnGetDriverInfo;
|
|
DD_GETDRIVERINFODATA GetDriverInfoData;
|
|
DWORD dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
DWORD dwSize;
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
pfnGetDriverInfo = peDirectDrawGlobal->HalInfo.GetDriverInfo;
|
|
|
|
if( ( pfnGetDriverInfo != NULL ) &&
|
|
(peDirectDrawGlobal->HalInfo.dwFlags & DDHALINFO_GETDRIVERINFOSET))
|
|
{
|
|
RtlZeroMemory(&GetDriverInfoData, sizeof(GetDriverInfoData));
|
|
|
|
GetDriverInfoData.dhpdev = peDirectDrawGlobal->dhpdev;
|
|
GetDriverInfoData.dwSize = sizeof(GetDriverInfoData);
|
|
GetDriverInfoData.guidInfo = *pGuid;
|
|
GetDriverInfoData.dwExpectedSize = cjSize;
|
|
GetDriverInfoData.lpvData = pvBuffer;
|
|
GetDriverInfoData.ddRVal = DDERR_CURRENTLYNOTAVAIL;
|
|
|
|
dwRet = pfnGetDriverInfo(&GetDriverInfoData);
|
|
}
|
|
|
|
if (dwRet == DDHAL_DRIVER_HANDLED &&
|
|
GetDriverInfoData.ddRVal == DD_OK)
|
|
{
|
|
if (pjSizeReturned != NULL)
|
|
{
|
|
*pjSizeReturned = GetDriverInfoData.dwActualSize;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
RtlZeroMemory(pvBuffer, cjSize);
|
|
|
|
if (pjSizeReturned != NULL)
|
|
{
|
|
*pjSizeReturned = 0;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdIoQueryInterface
|
|
*
|
|
* 12-Feb-1998 -by- Drew Bliss [drewb]
|
|
* Made vDdQueryMiniportDxApiSupport generic for QI requests.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdIoQueryInterface(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
const GUID* pguid,
|
|
DWORD cjInterface,
|
|
DWORD dwDesiredVersion,
|
|
INTERFACE* pInterface
|
|
)
|
|
{
|
|
BOOL bSuccess;
|
|
PDEVICE_OBJECT hDevice;
|
|
KEVENT event;
|
|
PIRP pIrp;
|
|
IO_STATUS_BLOCK Iosb;
|
|
PIO_STACK_LOCATION stack;
|
|
DDGETIRQINFO GetIrqInfo;
|
|
|
|
bSuccess = FALSE; // Assume failure
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal); // Synchronize call into miniport
|
|
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
hDevice = (PDEVICE_OBJECT) po.hScreen();
|
|
|
|
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
|
|
|
|
pIrp = IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS,
|
|
hDevice,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&event,
|
|
&Iosb);
|
|
if (pIrp != NULL)
|
|
{
|
|
pIrp->IoStatus.Status = Iosb.Status = STATUS_NOT_SUPPORTED;
|
|
|
|
stack = IoGetNextIrpStackLocation(pIrp);
|
|
|
|
stack->MajorFunction
|
|
= IRP_MJ_PNP;
|
|
|
|
stack->MinorFunction
|
|
= IRP_MN_QUERY_INTERFACE;
|
|
|
|
stack->Parameters.QueryInterface.InterfaceType
|
|
= pguid;
|
|
|
|
stack->Parameters.QueryInterface.Size
|
|
= (USHORT)cjInterface;
|
|
|
|
stack->Parameters.QueryInterface.Version
|
|
= (USHORT)dwDesiredVersion;
|
|
|
|
stack->Parameters.QueryInterface.Interface
|
|
= pInterface;
|
|
|
|
stack->Parameters.QueryInterface.InterfaceSpecificData
|
|
= NULL;
|
|
|
|
// Note that we allow newer interfaces to work with older system
|
|
// code so that new drivers can run on older systems.
|
|
|
|
if (NT_SUCCESS(IoCallDriver(hDevice, pIrp)))
|
|
{
|
|
if ((pInterface->Version >= dwDesiredVersion) &&
|
|
(pInterface->Size >= cjInterface) &&
|
|
(pInterface->Context != NULL))
|
|
{
|
|
bSuccess = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("bDdIoQueryInterface: "
|
|
"Driver returned invalid QueryInterface data.");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("bDdIoQueryInterface: Unable to build request.");
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdGetAllDriverInfo
|
|
*
|
|
* Makes GetDriverInfo HAL calls to determine capabilities of the device,
|
|
* such as for Direct3D or VPE.
|
|
*
|
|
* Assumes devlock already held.
|
|
*
|
|
* 16-Feb-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdGetAllDriverInfo(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
|
|
)
|
|
{
|
|
DWORD dwMaxVideoPorts;
|
|
ULONG cjMaxVideoPorts;
|
|
DDVIDEOPORTCAPS* pVideoPortCaps;
|
|
ULONG i;
|
|
DWORD dwRet;
|
|
DWORD dwOverride;
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
// Get driver override info:
|
|
|
|
dwOverride = po.dwDriverCapableOverride();
|
|
|
|
// Get DXAPI info:
|
|
|
|
vDdQueryMiniportDxApiSupport(peDirectDrawGlobal);
|
|
|
|
// Get AGP info:
|
|
|
|
if (!bDdIoQueryInterface(peDirectDrawGlobal,
|
|
&GUID_AGP_INTERFACE,
|
|
sizeof(AGP_INTERFACE),
|
|
AGP_INTERFACE_VERSION,
|
|
(INTERFACE *)
|
|
&peDirectDrawGlobal->AgpInterface))
|
|
{
|
|
RtlZeroMemory(&peDirectDrawGlobal->AgpInterface,
|
|
sizeof(peDirectDrawGlobal->AgpInterface));
|
|
}
|
|
|
|
if ((peDirectDrawGlobal->HalInfo.GetDriverInfo != NULL) &&
|
|
(peDirectDrawGlobal->HalInfo.dwFlags & DDHALINFO_GETDRIVERINFOSET))
|
|
{
|
|
// DX5 callbacks are never used on NT so we do not bother to ask the driver for them
|
|
// We simply zero them out
|
|
|
|
RtlZeroMemory(&peDirectDrawGlobal->D3dCallBacks2,
|
|
sizeof(peDirectDrawGlobal->D3dCallBacks2));
|
|
|
|
// Get D3DCallbacks3. If this fails the callbacks will
|
|
// be NULL. Also check if this driver is capable of doing D3D or not
|
|
|
|
if ((!(dwOverride & DRIVER_NOT_CAPABLE_D3D))
|
|
&&bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_D3DCallbacks3,
|
|
&peDirectDrawGlobal->D3dCallBacks3,
|
|
sizeof(peDirectDrawGlobal->D3dCallBacks3),
|
|
NULL))
|
|
{
|
|
// It needs to accept a new GUID
|
|
if (bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_D3DParseUnknownCommandCallback,
|
|
&D3DParseUnknownCommand, 0, NULL))
|
|
{
|
|
peDirectDrawGlobal->flDriverInfo |= DD_DRIVERINFO_D3DCALLBACKS3;
|
|
}
|
|
else
|
|
{
|
|
// If the GUID is not recognized, stub out Callbacks3
|
|
WARNING("vDdGetAllDriverInfo: Driver failed GUID_D3DParseUnknownCommandCallback but understood GUID_D3DCallbacks3");
|
|
RtlZeroMemory(&peDirectDrawGlobal->D3dCallBacks3,
|
|
sizeof(peDirectDrawGlobal->D3dCallBacks3));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Note: GUID_ZPixelFormats is not queried because kernel doesn't need to
|
|
// store the DDPIXELFORMATS data
|
|
|
|
// Get DXAPI ("Kernel-Mode") capabilities.
|
|
|
|
dwRet = DXERR_GENERIC;
|
|
if (bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_KernelCaps,
|
|
&peDirectDrawGlobal->DDKernelCaps,
|
|
sizeof(peDirectDrawGlobal->DDKernelCaps),
|
|
NULL))
|
|
{
|
|
/*
|
|
* They may have said that they have IRQ capabilites, but
|
|
* we need to make sure this is really the case. For this,
|
|
* we can call the GetIRQInfo function in the miniport.
|
|
*/
|
|
if( peDirectDrawGlobal->DxApiInterface.DxGetIrqInfo != NULL )
|
|
{
|
|
DDGETIRQINFO GetIRQInfo;
|
|
|
|
dwRet = peDirectDrawGlobal->DxApiInterface.DxGetIrqInfo(
|
|
peDirectDrawGlobal->HwDeviceExtension,
|
|
NULL,
|
|
&GetIRQInfo);
|
|
if( GetIRQInfo.dwFlags != IRQINFO_HANDLED )
|
|
{
|
|
dwRet = DXERR_GENERIC;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( dwRet != DX_OK )
|
|
{
|
|
peDirectDrawGlobal->DDKernelCaps.dwIRQCaps = 0;
|
|
peDirectDrawGlobal->DDKernelCaps.dwCaps &= ~( DDKERNELCAPS_AUTOFLIP |
|
|
DDKERNELCAPS_CAPTURE_SYSMEM | DDKERNELCAPS_CAPTURE_NONLOCALVIDMEM );
|
|
}
|
|
|
|
// Get VPE info:
|
|
|
|
dwMaxVideoPorts = peDirectDrawGlobal->HalInfo.ddCaps.dwMaxVideoPorts;
|
|
if (dwMaxVideoPorts != 0)
|
|
{
|
|
if (bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_VideoPortCallbacks,
|
|
&peDirectDrawGlobal->VideoPortCallBacks,
|
|
sizeof(peDirectDrawGlobal->VideoPortCallBacks),
|
|
NULL))
|
|
{
|
|
cjMaxVideoPorts = sizeof(DDVIDEOPORTCAPS) * dwMaxVideoPorts;
|
|
|
|
pVideoPortCaps = (DDVIDEOPORTCAPS*) PALLOCMEM(cjMaxVideoPorts,
|
|
'pddG');
|
|
if (pVideoPortCaps != NULL)
|
|
{
|
|
if (bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_VideoPortCaps,
|
|
pVideoPortCaps,
|
|
cjMaxVideoPorts,
|
|
NULL))
|
|
{
|
|
peDirectDrawGlobal->HalInfo.ddCaps.dwMaxVideoPorts
|
|
= dwMaxVideoPorts;
|
|
peDirectDrawGlobal->lpDDVideoPortCaps
|
|
= pVideoPortCaps;
|
|
peDirectDrawGlobal->flDriverInfo
|
|
|= DD_DRIVERINFO_VIDEOPORT;
|
|
|
|
for (i = 0; i < dwMaxVideoPorts; i++)
|
|
{
|
|
if (peDirectDrawGlobal->DDKernelCaps.dwIRQCaps
|
|
& (DDIRQ_VPORT0_VSYNC << (i * 2)) &&
|
|
(peDirectDrawGlobal->DDKernelCaps.dwCaps
|
|
& DDKERNELCAPS_AUTOFLIP))
|
|
{
|
|
// Can do software autoflipping.
|
|
|
|
pVideoPortCaps[i].dwCaps |= DDVPCAPS_AUTOFLIP;
|
|
pVideoPortCaps[i].dwNumAutoFlipSurfaces
|
|
= MAX_AUTOFLIP_BUFFERS;
|
|
if (pVideoPortCaps[i].dwCaps & DDVPCAPS_VBISURFACE)
|
|
{
|
|
pVideoPortCaps[i].dwNumVBIAutoFlipSurfaces
|
|
= MAX_AUTOFLIP_BUFFERS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RIP("vDdGetAllDriverInfo: Driver failed GUID_VideoPortCaps");
|
|
|
|
RtlZeroMemory(&peDirectDrawGlobal->VideoPortCallBacks,
|
|
sizeof(peDirectDrawGlobal->VideoPortCallBacks));
|
|
|
|
VFREEMEM(pVideoPortCaps);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get ColorControl info:
|
|
|
|
if (bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_ColorControlCallbacks,
|
|
&peDirectDrawGlobal->ColorControlCallBacks,
|
|
sizeof(peDirectDrawGlobal->ColorControlCallBacks),
|
|
NULL))
|
|
{
|
|
peDirectDrawGlobal->flDriverInfo |= DD_DRIVERINFO_COLORCONTROL;
|
|
}
|
|
|
|
// Get Miscellaneous info:
|
|
|
|
if (bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_MiscellaneousCallbacks,
|
|
&peDirectDrawGlobal->MiscellaneousCallBacks,
|
|
sizeof(peDirectDrawGlobal->MiscellaneousCallBacks),
|
|
NULL))
|
|
{
|
|
peDirectDrawGlobal->flDriverInfo |= DD_DRIVERINFO_MISCELLANEOUS;
|
|
}
|
|
|
|
// Get Miscellaneous2 info:
|
|
|
|
if (bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_Miscellaneous2Callbacks,
|
|
&peDirectDrawGlobal->Miscellaneous2CallBacks,
|
|
sizeof(peDirectDrawGlobal->Miscellaneous2CallBacks),
|
|
NULL))
|
|
{
|
|
peDirectDrawGlobal->flDriverInfo |= DD_DRIVERINFO_MISCELLANEOUS2;
|
|
}
|
|
else
|
|
{
|
|
// If the GUID is not recognized, stub out D3DCallbacks3...
|
|
RtlZeroMemory(&peDirectDrawGlobal->D3dCallBacks3,
|
|
sizeof(peDirectDrawGlobal->D3dCallBacks3));
|
|
// ... and clear the bit
|
|
peDirectDrawGlobal->flDriverInfo &= ~DD_DRIVERINFO_D3DCALLBACKS3;
|
|
// Stub out all other d3d driver info
|
|
RtlZeroMemory(&peDirectDrawGlobal->D3dDriverData,
|
|
sizeof(peDirectDrawGlobal->D3dDriverData));
|
|
RtlZeroMemory(&peDirectDrawGlobal->D3dCallBacks,
|
|
sizeof(peDirectDrawGlobal->D3dCallBacks));
|
|
RtlZeroMemory(&peDirectDrawGlobal->D3dBufCallbacks,
|
|
sizeof(peDirectDrawGlobal->D3dBufCallbacks));
|
|
}
|
|
|
|
// Get NT info:
|
|
|
|
if (bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_NTCallbacks,
|
|
&peDirectDrawGlobal->NTCallBacks,
|
|
sizeof(peDirectDrawGlobal->NTCallBacks),
|
|
NULL))
|
|
{
|
|
peDirectDrawGlobal->flDriverInfo |= DD_DRIVERINFO_NT;
|
|
}
|
|
|
|
// Get MoreCaps info:
|
|
|
|
if (bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_DDMoreCaps,
|
|
&peDirectDrawGlobal->MoreCaps,
|
|
sizeof(peDirectDrawGlobal->MoreCaps),
|
|
NULL))
|
|
{
|
|
peDirectDrawGlobal->flDriverInfo |= DD_DRIVERINFO_MORECAPS;
|
|
}
|
|
|
|
// Get PrivateDriverCaps info. If the driver is not capable of D3D
|
|
// then don't do it
|
|
|
|
if ((!(dwOverride & DRIVER_NOT_CAPABLE_D3D))
|
|
&&(bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_NTPrivateDriverCaps,
|
|
&peDirectDrawGlobal->PrivateCaps,
|
|
sizeof(peDirectDrawGlobal->PrivateCaps),
|
|
NULL)))
|
|
{
|
|
peDirectDrawGlobal->flDriverInfo |= DD_DRIVERINFO_PRIVATECAPS;
|
|
}
|
|
|
|
// Get DXAPI ("Kernel-Mode") call-backs. Note that we don't bother
|
|
// with a flag because user-mode never needs to know whether the
|
|
// driver has actually hooked these or not.
|
|
|
|
bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_KernelCallbacks,
|
|
&peDirectDrawGlobal->DxApiCallBacks,
|
|
sizeof(peDirectDrawGlobal->DxApiCallBacks),
|
|
NULL);
|
|
|
|
// Get MotionComp info:
|
|
|
|
if (bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_MotionCompCallbacks,
|
|
&peDirectDrawGlobal->MotionCompCallbacks,
|
|
sizeof(peDirectDrawGlobal->MotionCompCallbacks),
|
|
NULL))
|
|
{
|
|
peDirectDrawGlobal->flDriverInfo |= DD_DRIVERINFO_MOTIONCOMP;
|
|
}
|
|
}
|
|
|
|
// Determine if the device supports gamma ramps or not
|
|
|
|
peDirectDrawGlobal->HalInfo.ddCaps.dwCaps2 &= ~DDCAPS2_PRIMARYGAMMA;
|
|
if ((po.iDitherFormat() == BMF_8BPP) ||
|
|
((PPFNVALID(po, IcmSetDeviceGammaRamp)) &&
|
|
(po.flGraphicsCaps2() & GCAPS2_CHANGEGAMMARAMP)))
|
|
{
|
|
peDirectDrawGlobal->HalInfo.ddCaps.dwCaps2 |= DDCAPS2_PRIMARYGAMMA;
|
|
}
|
|
|
|
// Squish any ROP caps that the driver may have set so apps will
|
|
// know that they're not supported.
|
|
|
|
RtlZeroMemory(peDirectDrawGlobal->HalInfo.ddCaps.dwRops,
|
|
sizeof( peDirectDrawGlobal->HalInfo.ddCaps.dwRops ) );
|
|
RtlZeroMemory(peDirectDrawGlobal->HalInfo.ddCaps.dwSVBRops,
|
|
sizeof( peDirectDrawGlobal->HalInfo.ddCaps.dwSVBRops ) );
|
|
RtlZeroMemory(peDirectDrawGlobal->HalInfo.ddCaps.dwVSBRops,
|
|
sizeof( peDirectDrawGlobal->HalInfo.ddCaps.dwVSBRops ) );
|
|
RtlZeroMemory(peDirectDrawGlobal->HalInfo.ddCaps.dwSSBRops,
|
|
sizeof( peDirectDrawGlobal->HalInfo.ddCaps.dwSSBRops ) );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD dwDdSetAGPPolicy()
|
|
*
|
|
* Reads the DirectDraw AGP policy value from the registry and adjusts as
|
|
* necessary.
|
|
*
|
|
* Note: This policy only restricts the size per heap. If the driver exposes
|
|
* more than 1 heap, it should do extra work to determine reasonable heap
|
|
* sizes based on total physical memory and perhaps other data.
|
|
*
|
|
* 28-Sep-1999 -by- John Stephens [johnstep]
|
|
* Copied from llDdAssertModeTimeout().
|
|
\**************************************************************************/
|
|
|
|
#define AGP_BASE_MEMORY_PAGES ((64 * 1024 * 1024) / PAGE_SIZE)
|
|
|
|
// The following are the limits of an AGP reservation:
|
|
|
|
#define AGP_MINIMUM_MAX_PAGES ((8 * 1024 * 1024) / PAGE_SIZE)
|
|
#define AGP_MAXIMUM_MAX_PAGES ((256 * 1024 * 1024) / PAGE_SIZE)
|
|
|
|
DWORD
|
|
dwDdSetAgpPolicy(
|
|
)
|
|
{
|
|
HANDLE hkRegistry;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
NTSTATUS status;
|
|
DWORD Length;
|
|
DWORD Policy;
|
|
PKEY_VALUE_FULL_INFORMATION Information;
|
|
SYSTEM_BASIC_INFORMATION BasicInfo;
|
|
SYSINF_PAGE_COUNT PageCount;
|
|
|
|
status = ZwQuerySystemInformation(SystemBasicInformation,
|
|
(VOID*) &BasicInfo,
|
|
sizeof BasicInfo,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(status) ||
|
|
(BasicInfo.NumberOfPhysicalPages < AGP_MINIMUM_MAX_PAGES))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// By default, we let them use all of the memory minus 64 Meg
|
|
|
|
PageCount = BasicInfo.NumberOfPhysicalPages - AGP_BASE_MEMORY_PAGES;
|
|
if (PageCount < AGP_MAXIMUM_MAX_PAGES) {
|
|
Policy = (DWORD)PageCount;
|
|
} else {
|
|
Policy = AGP_MAXIMUM_MAX_PAGES;
|
|
}
|
|
|
|
if ((Policy < AGP_MINIMUM_MAX_PAGES) ||
|
|
(BasicInfo.NumberOfPhysicalPages < AGP_BASE_MEMORY_PAGES))
|
|
{
|
|
// But some drivers (nvidia) really need to have at least 8 Meg, so we
|
|
// need to give them at least that much.
|
|
Policy = AGP_MINIMUM_MAX_PAGES;
|
|
}
|
|
|
|
RtlInitUnicodeString(&UnicodeString,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\"
|
|
L"Control\\GraphicsDrivers");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL);
|
|
|
|
status = ZwOpenKey(&hkRegistry, GENERIC_READ, &ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
RtlInitUnicodeString(&UnicodeString, L"AGPPolicyMaxPages");
|
|
|
|
Length = sizeof(KEY_VALUE_FULL_INFORMATION) + sizeof(L"AGPPolicyMaxPages") +
|
|
sizeof(DWORD);
|
|
|
|
|
|
Information = (PKEY_VALUE_FULL_INFORMATION) PALLOCMEM(Length, ' ddG');
|
|
|
|
if (Information)
|
|
{
|
|
status = ZwQueryValueKey(hkRegistry,
|
|
&UnicodeString,
|
|
KeyValueFullInformation,
|
|
Information,
|
|
Length,
|
|
&Length);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
Policy = *( (LPDWORD) ((((PUCHAR)Information) +
|
|
Information->DataOffset)) );
|
|
}
|
|
|
|
VFREEMEM(Information);
|
|
}
|
|
|
|
ZwCloseKey(hkRegistry);
|
|
}
|
|
|
|
// Clamp policy maximum pages:
|
|
|
|
if (Policy < AGP_MINIMUM_MAX_PAGES)
|
|
{
|
|
Policy = 0;
|
|
}
|
|
else
|
|
{
|
|
Policy = min(Policy, AGP_MAXIMUM_MAX_PAGES);
|
|
if (BasicInfo.NumberOfPhysicalPages > AGP_BASE_MEMORY_PAGES)
|
|
{
|
|
Policy = (DWORD)min( Policy,
|
|
(BasicInfo.NumberOfPhysicalPages -
|
|
AGP_BASE_MEMORY_PAGES));
|
|
}
|
|
|
|
// Round down to the nearest 64 KB multiple and convert to bytes:
|
|
|
|
Policy = (Policy & ~0xF) * PAGE_SIZE;
|
|
}
|
|
|
|
return Policy;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdInitHeaps
|
|
*
|
|
* Initializes video memory heaps returned by the driver.
|
|
*
|
|
* Assumes devlock already held and AGP functions queried.
|
|
*
|
|
* 6-Feb-1998 -by- Drew Bliss [drewb]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdInitHeaps(EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal)
|
|
{
|
|
DWORD dwHeap;
|
|
VIDEOMEMORY* pHeap;
|
|
|
|
DDKHEAP(("DDKHEAP: Initializing %d heaps\n",
|
|
peDirectDrawGlobal->dwNumHeaps));
|
|
|
|
// Set the AGP policy here:
|
|
|
|
dwAGPPolicyMaxBytes = dwDdSetAgpPolicy();
|
|
|
|
// Initialize heaps which aren't preallocated.
|
|
pHeap = peDirectDrawGlobal->pvmList;
|
|
for (dwHeap = 0;
|
|
dwHeap < peDirectDrawGlobal->dwNumHeaps;
|
|
pHeap++, dwHeap++)
|
|
{
|
|
// If the current heap is an AGP heap but we were unable to
|
|
// get access to the AGP control functions then we can't use it,
|
|
// so remove it from the list.
|
|
//
|
|
// The heap is also disabled in the case where a driver reports
|
|
// a non-local heap but doesn't report non-local vidmem caps.
|
|
if ((pHeap->dwFlags & VIDMEM_ISNONLOCAL) &&
|
|
(peDirectDrawGlobal->AgpInterface.Context == NULL ||
|
|
(peDirectDrawGlobal->HalInfo.ddCaps.dwCaps2 &
|
|
DDCAPS2_NONLOCALVIDMEM) == 0))
|
|
{
|
|
DDKHEAP(("DDKHEAP: Disabling AGP heap %d\n", dwHeap));
|
|
|
|
pHeap->dwFlags |= VIDMEM_HEAPDISABLED;
|
|
}
|
|
else if (!(pHeap->dwFlags & VIDMEM_ISHEAP))
|
|
{
|
|
// Get any heap alignment restrictions from driver:
|
|
|
|
DD_GETHEAPALIGNMENTDATA GetHeapAlignmentData;
|
|
HEAPALIGNMENT* pHeapAlignment = NULL;
|
|
|
|
RtlZeroMemory(&GetHeapAlignmentData, sizeof GetHeapAlignmentData);
|
|
|
|
GetHeapAlignmentData.dwInstance =
|
|
(ULONG_PTR) peDirectDrawGlobal->dhpdev;
|
|
GetHeapAlignmentData.dwHeap = dwHeap;
|
|
GetHeapAlignmentData.ddRVal = DDERR_GENERIC;
|
|
GetHeapAlignmentData.Alignment.dwSize =
|
|
sizeof GetHeapAlignmentData.Alignment;
|
|
|
|
if (bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_GetHeapAlignment,
|
|
&GetHeapAlignmentData,
|
|
sizeof GetHeapAlignmentData,
|
|
NULL))
|
|
{
|
|
pHeapAlignment = &GetHeapAlignmentData.Alignment;
|
|
}
|
|
|
|
DDKHEAP(("DDKHEAP: Initializing heap %d, flags %X\n",
|
|
dwHeap, pHeap->dwFlags));
|
|
|
|
if (HeapVidMemInit(pHeap,
|
|
peDirectDrawGlobal->
|
|
HalInfo.vmiData.lDisplayPitch,
|
|
AGP_HDEV(peDirectDrawGlobal),
|
|
pHeapAlignment) == NULL)
|
|
{
|
|
DDKHEAP(("DDKHEAP: Heap %d failed init\n", dwHeap));
|
|
|
|
pHeap->dwFlags |= VIDMEM_HEAPDISABLED;
|
|
}
|
|
else
|
|
{
|
|
DDKHEAP(("DDKHEAP: Heap %d is %08X\n",
|
|
dwHeap, pHeap->lpHeap));
|
|
if (pHeap->dwFlags & VIDMEM_ISNONLOCAL)
|
|
{
|
|
pHeap->lpHeap->hdevAGP = AGP_HDEV(peDirectDrawGlobal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
ULONG ulHeaps=peDirectDrawGlobal->dwNumHeaps;
|
|
ULONG cjData=sizeof(DD_MORESURFACECAPS)-sizeof(DDSCAPSEX)*2+
|
|
ulHeaps*sizeof(DDSCAPSEX)*2;
|
|
// allocate memory in ddraw style, add some junk after data strucure
|
|
// so that not well behaved driver does not break the kernel.
|
|
PDD_MORESURFACECAPS pDDMoreSurfaceCaps=(PDD_MORESURFACECAPS)
|
|
PALLOCMEM(cjData+0x400,'pddG');
|
|
|
|
RtlZeroMemory(&peDirectDrawGlobal->MoreSurfaceCaps,
|
|
sizeof(peDirectDrawGlobal->MoreSurfaceCaps));
|
|
|
|
if (pDDMoreSurfaceCaps!=NULL)
|
|
{
|
|
RtlZeroMemory(pDDMoreSurfaceCaps, cjData);
|
|
pDDMoreSurfaceCaps->dwSize=cjData;
|
|
if (bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_DDMoreSurfaceCaps,
|
|
pDDMoreSurfaceCaps,
|
|
cjData,
|
|
&cjData))
|
|
{
|
|
// now fill ddscaps into heaps
|
|
// directdraw runtime does not expect the heap restrictions
|
|
ULONG cjCopy= (ULONG)min(sizeof(DD_MORESURFACECAPS)-sizeof(DDSCAPSEX)*2,cjData);
|
|
pDDMoreSurfaceCaps->dwSize=cjCopy;
|
|
RtlCopyMemory(&peDirectDrawGlobal->MoreSurfaceCaps,
|
|
pDDMoreSurfaceCaps,
|
|
cjCopy);
|
|
|
|
// now Copy ddxCapsex/ExAlt members to heaps...
|
|
pHeap = peDirectDrawGlobal->pvmList;
|
|
for (dwHeap = 0;
|
|
dwHeap < ulHeaps;
|
|
pHeap++, dwHeap++)
|
|
{
|
|
if (!(pHeap->dwFlags&VIDMEM_HEAPDISABLED))
|
|
{
|
|
RtlCopyMemory(
|
|
&pHeap->lpHeap->ddsCapsEx,
|
|
&pDDMoreSurfaceCaps->ddsExtendedHeapRestrictions[dwHeap].ddsCapsEx,
|
|
sizeof(DDSCAPSEX));
|
|
RtlCopyMemory(
|
|
&pHeap->lpHeap->ddsCapsExAlt,
|
|
&pDDMoreSurfaceCaps->ddsExtendedHeapRestrictions[dwHeap].ddsCapsExAlt,
|
|
sizeof(DDSCAPSEX));
|
|
}
|
|
}
|
|
peDirectDrawGlobal->flDriverInfo |= DD_DRIVERINFO_MORESURFACECAPS;
|
|
}
|
|
VFREEMEM(pDDMoreSurfaceCaps);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID UpdateNonLocalHeap
|
|
*
|
|
* Notifies the driver when the AGP heap information changes.
|
|
*
|
|
* 2-Mar-2001 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void UpdateNonLocalHeap(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
DWORD dwHeapIndex
|
|
)
|
|
{
|
|
DD_UPDATENONLOCALHEAPDATA UpdateNonLocalHeapData;
|
|
LPVIDMEM lpVidMem = &(peDirectDrawGlobal->pvmList[dwHeapIndex]);
|
|
|
|
UpdateNonLocalHeapData.lpDD = peDirectDrawGlobal;
|
|
UpdateNonLocalHeapData.dwHeap = dwHeapIndex;
|
|
UpdateNonLocalHeapData.fpGARTLin = lpVidMem->lpHeap->fpGARTLin;
|
|
UpdateNonLocalHeapData.fpGARTDev = lpVidMem->lpHeap->fpGARTDev;
|
|
UpdateNonLocalHeapData.ulPolicyMaxBytes = 0;
|
|
UpdateNonLocalHeapData.ddRVal = DDERR_GENERIC;
|
|
|
|
bDdGetDriverInfo(peDirectDrawGlobal,
|
|
&GUID_UpdateNonLocalHeap,
|
|
&UpdateNonLocalHeapData,
|
|
sizeof UpdateNonLocalHeapData,
|
|
NULL);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID InitAgpHeap
|
|
*
|
|
* We do not want to call AGPReserve in HeapVidMemInit since it is called on
|
|
* every mode change, so instead we have a seperate function that reserves the
|
|
* AGP memory and it is called after the rest of the heap is initialized.
|
|
*
|
|
* 22-Feb-2001 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
InitAgpHeap(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
DWORD dwHeapIndex,
|
|
HANDLE hdev
|
|
)
|
|
{
|
|
DWORD dwSize;
|
|
FLATPTR fpLinStart;
|
|
LARGE_INTEGER liDevStart;
|
|
PVOID pvReservation;
|
|
BOOL fIsUC;
|
|
BOOL fIsWC;
|
|
DWORD dwSizeReserved = 0;
|
|
LPVIDMEM lpVidMem = &(peDirectDrawGlobal->pvmList[dwHeapIndex]);
|
|
|
|
/*
|
|
* Compute the size of the heap.
|
|
*/
|
|
dwSize = lpVidMem->lpHeap->dwTotalSize;
|
|
DDASSERT( 0UL != dwSize );
|
|
|
|
if( lpVidMem->dwFlags & VIDMEM_ISWC )
|
|
{
|
|
fIsUC = FALSE;
|
|
fIsWC = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fIsUC = TRUE;
|
|
fIsWC = FALSE;
|
|
}
|
|
|
|
/*
|
|
* Allocate a bit mask to keep track of which pages have been
|
|
* committed or not.
|
|
*/
|
|
lpVidMem->lpHeap->dwAgpCommitMaskSize =
|
|
(GetHeapSizeInPages(lpVidMem, lpVidMem->lpHeap->stride) / BITS_IN_BYTE) + 1;
|
|
lpVidMem->lpHeap->pAgpCommitMask =
|
|
(BYTE*) PALLOCMEM(lpVidMem->lpHeap->dwAgpCommitMaskSize, 'pddG');
|
|
if( lpVidMem->lpHeap->pAgpCommitMask == NULL )
|
|
{
|
|
lpVidMem->dwFlags |= VIDMEM_HEAPDISABLED;
|
|
return;
|
|
}
|
|
|
|
if( !(dwSizeReserved = AGPReserve( hdev, dwSize, fIsUC, fIsWC,
|
|
&fpLinStart, &liDevStart,
|
|
&pvReservation )) )
|
|
{
|
|
VDPF(( 0, V, "Could not reserve a GART address range for a "
|
|
"linear heap of size 0x%08x", dwSize ));
|
|
VFREEMEM(lpVidMem->lpHeap->pAgpCommitMask);
|
|
lpVidMem->lpHeap->pAgpCommitMask = NULL;
|
|
lpVidMem->dwFlags |= VIDMEM_HEAPDISABLED;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
VDPF((4,V, "Allocated a GART address range starting at "
|
|
"0x%08x (linear) 0x%08x:0x%08x (physical) of size %d",
|
|
fpLinStart, liDevStart.HighPart, liDevStart.LowPart,
|
|
dwSizeReserved ));
|
|
}
|
|
|
|
if (dwSizeReserved != dwSize)
|
|
{
|
|
VDPF((0,V,"WARNING! This system required that the full "
|
|
"nonlocal aperture could not be reserved!"));
|
|
VDPF((0,V," Requested aperture:%08x, "
|
|
"Reserved aperture:%08x", dwSize, dwSizeReserved));
|
|
}
|
|
|
|
/*
|
|
* Update the heap for the new start address
|
|
* (and end address for a linear heap).
|
|
*/
|
|
lpVidMem->fpStart = fpLinStart;
|
|
if( lpVidMem->dwFlags & VIDMEM_ISLINEAR )
|
|
{
|
|
LPVMEML plh;
|
|
|
|
lpVidMem->fpEnd = ( fpLinStart + dwSizeReserved ) - 1UL;
|
|
lpVidMem->lpHeap->dwTotalSize = dwSizeReserved;
|
|
plh = (LPVMEML)lpVidMem->lpHeap->freeList;
|
|
if( ( plh != NULL ) && ( plh->ptr == 0 ) )
|
|
{
|
|
plh->ptr = lpVidMem->fpStart;
|
|
plh->size = dwSizeReserved;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LPVMEMR prh;
|
|
DWORD dwHeight;
|
|
|
|
DDASSERT( lpVidMem->dwFlags & VIDMEM_ISRECTANGULAR );
|
|
dwHeight = dwSizeReserved / lpVidMem->lpHeap->stride;
|
|
lpVidMem->lpHeap->dwTotalSize = dwHeight * lpVidMem->lpHeap->stride;
|
|
prh = (LPVMEMR)lpVidMem->lpHeap->freeList;
|
|
if( ( prh != NULL ) && ( prh->cy != 0x7fffffff ) )
|
|
{
|
|
prh->ptr = lpVidMem->fpStart;
|
|
prh->cy = dwHeight;
|
|
prh->size = (lpVidMem->dwWidth << 16 ) | dwHeight;
|
|
}
|
|
}
|
|
|
|
lpVidMem->lpHeap->fpGARTLin = fpLinStart;
|
|
// Fill in partial physical address for Win9x.
|
|
lpVidMem->lpHeap->fpGARTDev = liDevStart.LowPart;
|
|
// Fill in complete physical address for NT.
|
|
lpVidMem->lpHeap->liPhysAGPBase = liDevStart;
|
|
lpVidMem->lpHeap->pvPhysRsrv = pvReservation;
|
|
|
|
UpdateNonLocalHeap( peDirectDrawGlobal, dwHeapIndex );
|
|
|
|
} /* InitAgpHeap */
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID CheckAgpHeaps
|
|
*
|
|
* This funtion is called periodically to make sure that we initialize any
|
|
* uninitialized AGP heaps.
|
|
*
|
|
* 22-Feb-2001 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void CheckAgpHeaps(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
|
|
)
|
|
{
|
|
LPVIDMEM pHeap;
|
|
DWORD i;
|
|
|
|
pHeap = peDirectDrawGlobal->pvmList;
|
|
for( i = 0; i < peDirectDrawGlobal->dwNumHeaps; pHeap++, i++)
|
|
{
|
|
if ((pHeap->dwFlags & VIDMEM_ISNONLOCAL) &&
|
|
!(pHeap->dwFlags & VIDMEM_ISHEAP) &&
|
|
!(pHeap->dwFlags & VIDMEM_HEAPDISABLED) &&
|
|
(pHeap->lpHeap->pvPhysRsrv == NULL))
|
|
{
|
|
InitAgpHeap( peDirectDrawGlobal,
|
|
i,
|
|
AGP_HDEV(peDirectDrawGlobal));
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID MapAllAgpHeaps
|
|
*
|
|
* This funtion is virtually map all AGP heaps. It also virtually commits
|
|
* them to everything that is physically committed.
|
|
*
|
|
* 25-Apr-2001 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void MapAllAgpHeaps(
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal
|
|
)
|
|
{
|
|
if (peDirectDrawLocal->ppeMapAgp != NULL)
|
|
{
|
|
VIDEOMEMORY* pvmHeap;
|
|
DWORD i;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
for (i = 0; i < peDirectDrawGlobal->dwNumHeaps; i++)
|
|
{
|
|
pvmHeap = &peDirectDrawGlobal->pvmList[i];
|
|
|
|
if ((pvmHeap->dwFlags & VIDMEM_ISNONLOCAL) &&
|
|
!(pvmHeap->dwFlags & VIDMEM_ISHEAP) &&
|
|
!(pvmHeap->dwFlags & VIDMEM_HEAPDISABLED) &&
|
|
(pvmHeap->lpHeap != NULL) &&
|
|
(pvmHeap->lpHeap->pvPhysRsrv != NULL) &&
|
|
(peDirectDrawLocal->ppeMapAgp[i] == NULL))
|
|
{
|
|
// Reserve address space for the heap:
|
|
|
|
if (bDdMapAgpHeap(peDirectDrawLocal, pvmHeap))
|
|
{
|
|
if (peDirectDrawLocal->ppeMapAgp[i] != NULL)
|
|
{
|
|
AGPCommitAllVirtual (peDirectDrawLocal, pvmHeap, i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdDisableDriver
|
|
*
|
|
* Frees and destroys all driver state. Note that this may be called
|
|
* even while the driver is still only partially enabled.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdDisableDriver(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
|
|
)
|
|
{
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
if (peDirectDrawGlobal->pvmList != NULL)
|
|
{
|
|
DWORD dwHeap;
|
|
VIDEOMEMORY* pHeap;
|
|
|
|
// Shut down heaps.
|
|
|
|
DDKHEAP(("DDKHEAP: Shutting down %d heaps\n",
|
|
peDirectDrawGlobal->dwNumHeaps));
|
|
|
|
pHeap = peDirectDrawGlobal->pvmList;
|
|
for (dwHeap = 0;
|
|
dwHeap < peDirectDrawGlobal->dwNumHeaps;
|
|
pHeap++, dwHeap++)
|
|
{
|
|
if ((pHeap->dwFlags & VIDMEM_HEAPDISABLED) == 0 &&
|
|
pHeap->lpHeap != NULL)
|
|
{
|
|
DDKHEAP(("DDKHEAP: Uninitializing heap %d\n", dwHeap));
|
|
|
|
HeapVidMemFini(pHeap, AGP_HDEV(peDirectDrawGlobal));
|
|
}
|
|
}
|
|
|
|
VFREEMEM(peDirectDrawGlobal->pvmList);
|
|
peDirectDrawGlobal->pvmList = NULL;
|
|
}
|
|
|
|
if (peDirectDrawGlobal->pdwFourCC != NULL)
|
|
{
|
|
VFREEMEM(peDirectDrawGlobal->pdwFourCC);
|
|
peDirectDrawGlobal->pdwFourCC = NULL;
|
|
}
|
|
|
|
if (peDirectDrawGlobal->lpDDVideoPortCaps != NULL)
|
|
{
|
|
|
|
VFREEMEM(peDirectDrawGlobal->lpDDVideoPortCaps);
|
|
peDirectDrawGlobal->lpDDVideoPortCaps = NULL;
|
|
}
|
|
|
|
if (peDirectDrawGlobal->hDxApi != NULL)
|
|
{
|
|
vDdUnloadDxApiImage(peDirectDrawGlobal);
|
|
}
|
|
|
|
if (peDirectDrawGlobal->hdcCache != NULL)
|
|
{
|
|
// need to chage to 'current' since while it's in cache, it's 'none'
|
|
DxEngSetDCOwner((HDC) peDirectDrawGlobal->hdcCache, OBJECT_OWNER_CURRENT);
|
|
DxEngDeleteDC((HDC) peDirectDrawGlobal->hdcCache, TRUE);
|
|
peDirectDrawGlobal->hdcCache = NULL;
|
|
}
|
|
|
|
if (peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_DRIVER_ENABLED)
|
|
{
|
|
peDirectDrawGlobal->fl &= ~DD_GLOBAL_FLAG_DRIVER_ENABLED;
|
|
|
|
(*PPFNDRV(po, DisableDirectDraw))(po.dhpdev());
|
|
}
|
|
|
|
RtlZeroMemory((DD_DIRECTDRAW_GLOBAL_DRIVER_DATA*) peDirectDrawGlobal,
|
|
sizeof(DD_DIRECTDRAW_GLOBAL_DRIVER_DATA));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdEnableDriver
|
|
*
|
|
* Calls the driver's DrvGetDirectDrawInfo and DrvEnableDirectDraw
|
|
* functions to enable and initialize the driver and mode dependent
|
|
* portions of the global DirectDraw object.
|
|
*
|
|
* Assumes devlock already held.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdEnableDriver(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
|
|
)
|
|
{
|
|
BOOL bSuccess;
|
|
PFN_DrvGetDirectDrawInfo pfnGetDirectDrawInfo;
|
|
PFN_DrvEnableDirectDraw pfnEnableDirectDraw;
|
|
PFN_DrvDisableDirectDraw pfnDisableDirectDraw;
|
|
DWORD dwNumHeaps;
|
|
DWORD dwNumFourCC;
|
|
VIDEOMEMORY* pvmList;
|
|
DWORD* pdwFourCC;
|
|
ULONG iDitherFormat;
|
|
DWORD dw;
|
|
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
EDD_DEVLOCK eDevLock(peDirectDrawGlobal);
|
|
|
|
// Call the driver to see what it can do:
|
|
|
|
pfnGetDirectDrawInfo = PPFNDRV(po, GetDirectDrawInfo);
|
|
pfnEnableDirectDraw = PPFNDRV(po, EnableDirectDraw);
|
|
pfnDisableDirectDraw = PPFNDRV(po, DisableDirectDraw);
|
|
|
|
// To support DirectDraw, the driver must hook all three required
|
|
// DirectDraw functions.
|
|
|
|
bSuccess = ((pfnGetDirectDrawInfo != NULL) &&
|
|
(pfnEnableDirectDraw != NULL) &&
|
|
(pfnDisableDirectDraw != NULL));
|
|
|
|
dwNumHeaps = 0;
|
|
dwNumFourCC = 0;
|
|
|
|
peDirectDrawGlobal->fl &= ~DD_GLOBAL_FLAG_DRIVER_ENABLED;
|
|
|
|
// Do the first DrvGetDirectDrawInfo query for this PDEV to
|
|
// determine the number of heaps and the number of FourCC
|
|
// codes that the driver supports, so that we know how
|
|
// much memory to allocate:
|
|
|
|
if ((bSuccess) &&
|
|
(pfnGetDirectDrawInfo((DHPDEV) peDirectDrawGlobal->dhpdev,
|
|
&peDirectDrawGlobal->HalInfo,
|
|
&dwNumHeaps,
|
|
NULL,
|
|
&dwNumFourCC,
|
|
NULL)))
|
|
{
|
|
pvmList = NULL;
|
|
pdwFourCC = NULL;
|
|
|
|
DDKHEAP(("DDKHEAP: Driver reports dwNumHeaps %d\n", dwNumHeaps));
|
|
|
|
if (dwNumHeaps != 0)
|
|
{
|
|
pvmList = (VIDEOMEMORY*)
|
|
PALLOCMEM(sizeof(VIDEOMEMORY) * dwNumHeaps, 'vddG');
|
|
peDirectDrawGlobal->dwNumHeaps = dwNumHeaps;
|
|
peDirectDrawGlobal->pvmList = pvmList;
|
|
|
|
if (pvmList == NULL)
|
|
bSuccess = FALSE;
|
|
}
|
|
|
|
if (dwNumFourCC != 0)
|
|
{
|
|
pdwFourCC = (DWORD*)
|
|
PALLOCMEM(sizeof(DWORD) * dwNumFourCC, 'fddG');
|
|
peDirectDrawGlobal->dwNumFourCC = dwNumFourCC;
|
|
peDirectDrawGlobal->pdwFourCC = pdwFourCC;
|
|
|
|
if (pdwFourCC == NULL)
|
|
bSuccess = FALSE;
|
|
}
|
|
|
|
if (bSuccess)
|
|
{
|
|
// Do the second DrvGetDirectDrawInfo that actually
|
|
// gets all the data:
|
|
|
|
if (pfnGetDirectDrawInfo((DHPDEV) peDirectDrawGlobal->dhpdev,
|
|
&peDirectDrawGlobal->HalInfo,
|
|
&dwNumHeaps,
|
|
pvmList,
|
|
&dwNumFourCC,
|
|
pdwFourCC))
|
|
{
|
|
// Ensure that the driver doesn't give us an invalid address
|
|
// for its primary surface (like a user-mode address or NULL):
|
|
if (peDirectDrawGlobal->HalInfo.vmiData.pvPrimary != NULL)
|
|
{
|
|
dw = *((volatile DWORD *) peDirectDrawGlobal->HalInfo.vmiData.pvPrimary);
|
|
*((volatile DWORD *) peDirectDrawGlobal->HalInfo.vmiData.pvPrimary) = 0xabcdabcd;
|
|
*((volatile DWORD *) peDirectDrawGlobal->HalInfo.vmiData.pvPrimary) = dw;
|
|
|
|
if (pfnEnableDirectDraw((DHPDEV) peDirectDrawGlobal->dhpdev,
|
|
&peDirectDrawGlobal->CallBacks,
|
|
&peDirectDrawGlobal->SurfaceCallBacks,
|
|
&peDirectDrawGlobal->PaletteCallBacks))
|
|
{
|
|
// Check the driver's capability status
|
|
DWORD dwOverride = po.dwDriverCapableOverride();
|
|
|
|
// check for D3D support here
|
|
if ( (!(dwOverride & DRIVER_NOT_CAPABLE_D3D))
|
|
&&(peDirectDrawGlobal->HalInfo.dwSize == sizeof(DD_HALINFO)) )
|
|
{
|
|
// for ease of porting, NT5 HALINFO has the same pointers
|
|
// to D3D data as DX5
|
|
if(peDirectDrawGlobal->HalInfo.lpD3DGlobalDriverData != NULL &&
|
|
((D3DNTHAL_GLOBALDRIVERDATA*)
|
|
peDirectDrawGlobal->HalInfo.lpD3DGlobalDriverData)->dwSize ==
|
|
sizeof(D3DNTHAL_GLOBALDRIVERDATA))
|
|
{
|
|
peDirectDrawGlobal->D3dDriverData =
|
|
*(D3DNTHAL_GLOBALDRIVERDATA*)peDirectDrawGlobal->HalInfo.lpD3DGlobalDriverData;
|
|
if( peDirectDrawGlobal->HalInfo.lpD3DHALCallbacks != NULL &&
|
|
((D3DNTHAL_CALLBACKS*)peDirectDrawGlobal->HalInfo.lpD3DHALCallbacks)->dwSize ==
|
|
sizeof(D3DNTHAL_CALLBACKS))
|
|
{
|
|
peDirectDrawGlobal->D3dCallBacks =
|
|
*(D3DNTHAL_CALLBACKS*)peDirectDrawGlobal->HalInfo.lpD3DHALCallbacks;
|
|
|
|
if( peDirectDrawGlobal->HalInfo.lpD3DBufCallbacks != NULL &&
|
|
((PDD_D3DBUFCALLBACKS)peDirectDrawGlobal->HalInfo.lpD3DBufCallbacks)->dwSize ==
|
|
sizeof(DD_D3DBUFCALLBACKS))
|
|
{
|
|
peDirectDrawGlobal->D3dBufCallbacks =
|
|
*(PDD_D3DBUFCALLBACKS)peDirectDrawGlobal->HalInfo.lpD3DBufCallbacks;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// D3DCaps succeeded but D3DCallbacks didn't, so we
|
|
// must zero D3DCaps:
|
|
|
|
RtlZeroMemory(&peDirectDrawGlobal->D3dDriverData,
|
|
sizeof(peDirectDrawGlobal->D3dDriverData));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Use the GetDriverInfo HAL call to query any
|
|
// additional capabilities such as for Direct3D or
|
|
// VPE:
|
|
|
|
if (bDdGetAllDriverInfo(peDirectDrawGlobal))
|
|
{
|
|
if (bDdValidateDriverData(peDirectDrawGlobal))
|
|
{
|
|
// Initialize as many heaps as possible.
|
|
vDdInitHeaps(peDirectDrawGlobal);
|
|
|
|
peDirectDrawGlobal->fl |= DD_GLOBAL_FLAG_DRIVER_ENABLED;
|
|
return;
|
|
}
|
|
}
|
|
|
|
pfnDisableDirectDraw((DHPDEV) peDirectDrawGlobal->dhpdev);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("vDdEnableDriver: Driver returned invalid vmiData.pvPrimary\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Something didn't work, so zero out all of the caps that we may have
|
|
// gotten before the failure occurred.
|
|
|
|
peDirectDrawGlobal->flDriver = 0;
|
|
peDirectDrawGlobal->flDriverInfo = 0;
|
|
if (peDirectDrawGlobal->pdwFourCC != NULL)
|
|
{
|
|
VFREEMEM(peDirectDrawGlobal->pdwFourCC);
|
|
peDirectDrawGlobal->pdwFourCC = NULL;
|
|
}
|
|
peDirectDrawGlobal->dwNumFourCC = 0;
|
|
|
|
if (peDirectDrawGlobal->pvmList != NULL)
|
|
{
|
|
VFREEMEM(peDirectDrawGlobal->pvmList);
|
|
peDirectDrawGlobal->pvmList = NULL;
|
|
}
|
|
peDirectDrawGlobal->dwNumHeaps = 0;
|
|
|
|
RtlZeroMemory( &peDirectDrawGlobal->DxApiInterface,
|
|
sizeof( peDirectDrawGlobal->DxApiInterface ) );
|
|
RtlZeroMemory( &peDirectDrawGlobal->AgpInterface,
|
|
sizeof( peDirectDrawGlobal->AgpInterface ) );
|
|
RtlZeroMemory( &peDirectDrawGlobal->DDKernelCaps,
|
|
sizeof( peDirectDrawGlobal->DDKernelCaps ) );
|
|
RtlZeroMemory( &peDirectDrawGlobal->DxApiCallBacks,
|
|
sizeof( peDirectDrawGlobal->DxApiCallBacks ) );
|
|
RtlZeroMemory(&peDirectDrawGlobal->D3dDriverData,
|
|
sizeof(peDirectDrawGlobal->D3dDriverData));
|
|
RtlZeroMemory(&peDirectDrawGlobal->CallBacks,
|
|
sizeof(peDirectDrawGlobal->CallBacks));
|
|
RtlZeroMemory(&peDirectDrawGlobal->D3dCallBacks,
|
|
sizeof(peDirectDrawGlobal->D3dCallBacks));
|
|
RtlZeroMemory(&peDirectDrawGlobal->D3dBufCallbacks,
|
|
sizeof(peDirectDrawGlobal->D3dBufCallbacks));
|
|
RtlZeroMemory(&peDirectDrawGlobal->SurfaceCallBacks,
|
|
sizeof(peDirectDrawGlobal->SurfaceCallBacks));
|
|
RtlZeroMemory(&peDirectDrawGlobal->PaletteCallBacks,
|
|
sizeof(peDirectDrawGlobal->PaletteCallBacks));
|
|
RtlZeroMemory(&peDirectDrawGlobal->HalInfo,
|
|
sizeof(peDirectDrawGlobal->HalInfo));
|
|
|
|
peDirectDrawGlobal->HalInfo.dwSize =
|
|
sizeof(peDirectDrawGlobal->HalInfo);
|
|
peDirectDrawGlobal->HalInfo.ddCaps.dwSize =
|
|
sizeof(peDirectDrawGlobal->HalInfo.ddCaps);
|
|
peDirectDrawGlobal->HalInfo.ddCaps.dwCaps = DDCAPS_NOHARDWARE;
|
|
|
|
// Okay, we can't use the driver. Initialize what information we need
|
|
// from the PDEV so that system memory surfaces may still be used:
|
|
|
|
iDitherFormat = po.iDitherFormat();
|
|
if (iDitherFormat == BMF_4BPP)
|
|
{
|
|
peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount = 4;
|
|
}
|
|
else if (iDitherFormat == BMF_8BPP)
|
|
{
|
|
peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount = 8;
|
|
}
|
|
else if (iDitherFormat == BMF_16BPP)
|
|
{
|
|
peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount = 16;
|
|
}
|
|
else if (iDitherFormat == BMF_24BPP)
|
|
{
|
|
peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount = 24;
|
|
}
|
|
else if (iDitherFormat == BMF_32BPP)
|
|
{
|
|
peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount = 32;
|
|
}
|
|
else
|
|
{
|
|
RIP("Invalid iDitherFormat()");
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdIncrementReferenceCount
|
|
*
|
|
* Devlock must be held.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdIncrementReferenceCount(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
|
|
)
|
|
{
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
peDirectDrawGlobal->cDriverReferences++;
|
|
|
|
if (peDirectDrawGlobal->cDriverReferences == 1)
|
|
{
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
// Add a reference to the PDEV so that it won't be deleted
|
|
// until the last D3D structure is freed. We do this
|
|
// so that on dynamic mode changes, we can keep the active
|
|
// DirectDraw driver state around. This is so that if we ever
|
|
// return to the original mode, we can resume any Direct3D
|
|
// accelerations exactly where we were originally.
|
|
//
|
|
// The DirectDraw convention is that if an accelerated Direct3D
|
|
// application is started at 640x480, and the mode changes to
|
|
// 800x600, the application stops drawing (unless it recreates
|
|
// all its execute buffers and all other DirectX state). But if
|
|
// the display is returned back to the original 640x480 mode, all
|
|
// the application has to do is 'restore' its surfaces, and it can
|
|
// keep running.
|
|
//
|
|
// To allow this we have to keep around the driver's 640x480
|
|
// instance even when the display is 800x600. But if the
|
|
// application terminated while at 800x600, we would have to clean
|
|
// up the 640x480 driver instance. Once that happens, the 640x480
|
|
// PDEV can be completely deleted. This is why we reference
|
|
// count the PDEV:
|
|
|
|
po.vReferencePdev();
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdDecrementReferenceCount
|
|
*
|
|
* Devlock must not be held entering the function if PDEV may be unloaded.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdDecrementReferenceCount(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
|
|
)
|
|
{
|
|
BOOL bUnreference = FALSE;
|
|
|
|
{
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal->hdev);
|
|
|
|
ASSERTGDI(peDirectDrawGlobal->cDriverReferences > 0,
|
|
"Weird reference count");
|
|
|
|
if (--peDirectDrawGlobal->cDriverReferences == 0)
|
|
{
|
|
bUnreference = TRUE;
|
|
}
|
|
}
|
|
|
|
if (bUnreference)
|
|
{
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
// If this dev lock is not held then we may free this driver.
|
|
po.vUnreferencePdev();
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* LONGLONG llDdAssertModeTimeout()
|
|
*
|
|
* Reads the DirectDraw timeout value from the registry.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Lifted it from AndreVa's code.
|
|
\**************************************************************************/
|
|
|
|
LONGLONG
|
|
llDdAssertModeTimeout(
|
|
)
|
|
{
|
|
HANDLE hkRegistry;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UnicodeString;
|
|
NTSTATUS status;
|
|
LONGLONG llTimeout;
|
|
DWORD Length;
|
|
PKEY_VALUE_FULL_INFORMATION Information;
|
|
|
|
llTimeout = 0;
|
|
|
|
RtlInitUnicodeString(&UnicodeString,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\"
|
|
L"Control\\GraphicsDrivers\\DCI");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL);
|
|
|
|
status = ZwOpenKey(&hkRegistry, GENERIC_READ, &ObjectAttributes);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
RtlInitUnicodeString(&UnicodeString, L"Timeout");
|
|
|
|
Length = sizeof(KEY_VALUE_FULL_INFORMATION) + sizeof(L"Timeout") +
|
|
sizeof(DWORD);
|
|
|
|
Information = (PKEY_VALUE_FULL_INFORMATION) PALLOCMEM(Length, ' ddG');
|
|
|
|
if (Information)
|
|
{
|
|
status = ZwQueryValueKey(hkRegistry,
|
|
&UnicodeString,
|
|
KeyValueFullInformation,
|
|
Information,
|
|
Length,
|
|
&Length);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
llTimeout = ((LONGLONG) -10000) * 1000 * (
|
|
*(LPDWORD) ((((PUCHAR)Information) +
|
|
Information->DataOffset)));
|
|
}
|
|
|
|
VFREEMEM(Information);
|
|
}
|
|
|
|
ZwCloseKey(hkRegistry);
|
|
}
|
|
|
|
return(llTimeout);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdMapAgpHeap
|
|
*
|
|
* Maps an AGP heap into a virtual address space.
|
|
*
|
|
* 25-Aug-1999 -by- John Stephens [johnstep]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdMapAgpHeap(
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal,
|
|
VIDEOMEMORY* pvmHeap
|
|
)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_VMEMMAPPING* peMap;
|
|
BYTE* pAgpVirtualCommitMask;
|
|
DWORD dwAgpVirtualCommitMaskSize;
|
|
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
peMap = (EDD_VMEMMAPPING*) PALLOCMEM(sizeof(EDD_VMEMMAPPING), ' ddG');
|
|
|
|
dwAgpVirtualCommitMaskSize = pvmHeap->lpHeap->dwAgpCommitMaskSize;
|
|
if (dwAgpVirtualCommitMaskSize > 0)
|
|
{
|
|
pAgpVirtualCommitMask = (BYTE*)PALLOCMEM(dwAgpVirtualCommitMaskSize,
|
|
' ddG');
|
|
}
|
|
else
|
|
{
|
|
pAgpVirtualCommitMask = NULL;
|
|
}
|
|
if (pAgpVirtualCommitMask == NULL)
|
|
{
|
|
VFREEMEM(peMap);
|
|
peMap = NULL;
|
|
}
|
|
|
|
if (peMap)
|
|
{
|
|
peMap->pvVirtAddr =
|
|
peDirectDrawGlobal->AgpInterface.AgpServices.
|
|
AgpReserveVirtual(peDirectDrawGlobal->AgpInterface.Context,
|
|
NtCurrentProcess(),
|
|
pvmHeap->lpHeap->pvPhysRsrv,
|
|
&peMap->pvReservation);
|
|
|
|
if (peMap->pvVirtAddr != NULL)
|
|
{
|
|
peMap->cReferences = 1;
|
|
peMap->fl = DD_VMEMMAPPING_FLAG_AGP;
|
|
peMap->ulMapped = 0;
|
|
peMap->iHeapIndex = (DWORD)
|
|
(pvmHeap - peDirectDrawGlobal->pvmList);
|
|
peMap->pAgpVirtualCommitMask = pAgpVirtualCommitMask;
|
|
peMap->dwAgpVirtualCommitMaskSize = dwAgpVirtualCommitMaskSize;
|
|
|
|
ASSERTGDI(peDirectDrawLocal->
|
|
ppeMapAgp[peMap->iHeapIndex] == NULL,
|
|
"Heap already mapped");
|
|
|
|
peDirectDrawLocal->ppeMapAgp[peMap->iHeapIndex] = peMap;
|
|
peDirectDrawLocal->iAgpHeapsMapped++;
|
|
|
|
DDKHEAP(("DDKHEAP: Res %08X reserved %08X, size %X\n",
|
|
peMap->pvReservation, peMap->pvVirtAddr,
|
|
pvmHeap->lpHeap->dwTotalSize));
|
|
|
|
bSuccess = TRUE;
|
|
}
|
|
else
|
|
{
|
|
VFREEMEM(peMap);
|
|
}
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdUnmapMemory
|
|
*
|
|
* Deletes the user mode mapping of the frame buffer.
|
|
* We may be in a different process from the one in which
|
|
* the mapping was initially created in.
|
|
*
|
|
* The devlock must be held to call this function.
|
|
*
|
|
* Note: This should only be called from vDdUnreferenceVirtualMap
|
|
*
|
|
* 1-Oct-1998 -by- Anuj Gosalia [anujg]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdUnmapMemory(
|
|
EDD_VMEMMAPPING* peMap,
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
HANDLE ProcessHandle
|
|
)
|
|
{
|
|
DD_MAPMEMORYDATA MapMemoryData;
|
|
DWORD dwRet;
|
|
NTSTATUS Status;
|
|
|
|
DDKHEAP(("vDdUnmapMemory: peDirectDrawGlobal=%x, fpProcess=%x\n",
|
|
peDirectDrawGlobal, peMap->fpProcess));
|
|
|
|
// Call driver to unmap memory:
|
|
|
|
MapMemoryData.lpDD = peDirectDrawGlobal;
|
|
MapMemoryData.bMap = FALSE;
|
|
MapMemoryData.hProcess = ProcessHandle;
|
|
MapMemoryData.fpProcess = peMap->fpProcess;
|
|
|
|
dwRet = peDirectDrawGlobal->CallBacks.MapMemory(&MapMemoryData);
|
|
|
|
ASSERTGDI((dwRet == DDHAL_DRIVER_NOTHANDLED) ||
|
|
(MapMemoryData.ddRVal == DD_OK),
|
|
"Driver failed DirectDraw memory unmap\n");
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdUnmapAgpHeap
|
|
*
|
|
* Decommits all virtual memory in an AGP heap, then releases the heap
|
|
* mapping. If the AGP heap is now empty, this function will decommit the
|
|
* physical memory as well.
|
|
*
|
|
* Note: This should only be called from vDdUnreferenceVirtualMap
|
|
*
|
|
* 19-Jan-1999 -by- John Stephens [johnstep]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdUnmapAgpHeap(
|
|
EDD_VMEMMAPPING* peMap,
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal
|
|
)
|
|
{
|
|
VIDEOMEMORY* pvmHeap;
|
|
ULONG ulOffs;
|
|
BOOL bSuccess;
|
|
ULONG ulPages;
|
|
ULONG ulHeapPages;
|
|
|
|
pvmHeap = peDirectDrawGlobal->pvmList + peMap->iHeapIndex;
|
|
|
|
ASSERTGDI(peMap != NULL,
|
|
"Request to unmap an AGP heap which has not been mapped");
|
|
ASSERTGDI(pvmHeap->lpHeap->pvPhysRsrv != NULL,
|
|
"AGP reservation context is NULL in heap");
|
|
|
|
if (!(peDirectDrawLocal->fl & DD_LOCAL_DISABLED))
|
|
{
|
|
bSuccess = AGPDecommitVirtual( peMap,
|
|
peDirectDrawGlobal,
|
|
peDirectDrawLocal,
|
|
pvmHeap->lpHeap->dwTotalSize);
|
|
|
|
peDirectDrawGlobal->AgpInterface.AgpServices.
|
|
AgpReleaseVirtual(peDirectDrawGlobal->AgpInterface.Context,
|
|
peMap->pvReservation);
|
|
|
|
peDirectDrawLocal->iAgpHeapsMapped--;
|
|
}
|
|
|
|
// If the heap is now empty but memory is still committed, go ahead and
|
|
// decommit all the physical AGP memory:
|
|
|
|
if ((pvmHeap->lpHeap->allocList == NULL) &&
|
|
(pvmHeap->lpHeap->dwCommitedSize > 0))
|
|
{
|
|
DWORD dwTemp;
|
|
EDD_DIRECTDRAW_LOCAL* peTempLocal;
|
|
EDD_VMEMMAPPING* peTempMap;
|
|
|
|
// We may have other processes that have virtual commits outstanding
|
|
// even though they didn't allocate any AGP memory, so we can
|
|
// decommit them now.
|
|
|
|
peTempLocal = peDirectDrawGlobal->peDirectDrawLocalList;
|
|
while (peTempLocal != NULL )
|
|
{
|
|
if (peTempLocal != peDirectDrawLocal)
|
|
{
|
|
if ((peTempLocal->ppeMapAgp != NULL) &&
|
|
!(peTempLocal->fl & DD_LOCAL_DISABLED))
|
|
{
|
|
peTempMap = peTempLocal->ppeMapAgp[peMap->iHeapIndex];
|
|
if (peTempMap != NULL)
|
|
{
|
|
AGPDecommitVirtual( peTempMap,
|
|
peDirectDrawGlobal,
|
|
peTempLocal,
|
|
pvmHeap->lpHeap->dwTotalSize);
|
|
}
|
|
}
|
|
}
|
|
peTempLocal = peTempLocal->peDirectDrawLocalNext;
|
|
}
|
|
|
|
bSuccess = AGPDecommitAll(
|
|
AGP_HDEV(peDirectDrawGlobal),
|
|
pvmHeap->lpHeap->pvPhysRsrv,
|
|
pvmHeap->lpHeap->pAgpCommitMask,
|
|
pvmHeap->lpHeap->dwAgpCommitMaskSize,
|
|
&dwTemp,
|
|
pvmHeap->lpHeap->dwTotalSize);
|
|
|
|
ASSERTGDI(bSuccess, "Failed to decommit AGP memory");
|
|
|
|
pvmHeap->lpHeap->dwCommitedSize = 0;
|
|
}
|
|
else
|
|
{
|
|
CleanupAgpCommits( pvmHeap, pvmHeap->lpHeap->hdevAGP,
|
|
peDirectDrawGlobal, peMap->iHeapIndex );
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdUnreferenceVirtualMap
|
|
*
|
|
* 24-Aug-1999 -by- John Stephens [johnstep]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdUnreferenceVirtualMap(
|
|
EDD_VMEMMAPPING* peMap,
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal,
|
|
HANDLE ProcessHandle,
|
|
BOOL bMapToDummyPage
|
|
)
|
|
{
|
|
BOOL bUnmapMemory = FALSE;
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
// If this was the last surface holding a pointer in the mapping we can
|
|
// can free it now. This involves calling the driver since it was the
|
|
// one who created the mapping in the first place. If this is not the
|
|
// last reference, and the memory has not been aliased yet, do so now:
|
|
|
|
if (--(peMap->cReferences) == 0)
|
|
{
|
|
bUnmapMemory = TRUE;
|
|
}
|
|
else if (!(peMap->fl & DD_VMEMMAPPING_FLAG_ALIASED) && bMapToDummyPage)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
EngAcquireSemaphore(ghsemDummyPage);
|
|
|
|
if (gpDummyPage == NULL)
|
|
{
|
|
// Allocate dummy page which is used to map all disabled user
|
|
// mode vid mem mapping to:
|
|
|
|
gpDummyPage = ExAllocatePoolWithTag(
|
|
(POOL_TYPE)(SESSION_POOL_MASK | NonPagedPool),
|
|
PAGE_SIZE, 'DddG');
|
|
|
|
if (gpDummyPage == NULL)
|
|
{
|
|
WARNING("vDdUnreferenceVirtualMap: could not allocate dummy page");
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
else
|
|
{
|
|
ASSERTGDI(((ULONG_PTR)gpDummyPage & (PAGE_SIZE - 1)) == 0,
|
|
"vDdUnreferenceVirtualMap: "
|
|
"Dummy page is not page aligned\n");
|
|
DDKHEAP(("Allocated dummy page\n"));
|
|
gcDummyPageRefCnt = 0;
|
|
}
|
|
}
|
|
|
|
if (gpDummyPage != NULL)
|
|
{
|
|
DDKHEAP(("vDdUnreferenceVirtualMap: "
|
|
"Attempting to remap vid mem to dummy page\n"));
|
|
|
|
// There are outstanding locks to this memory. Map it to a dummy
|
|
// page and proceed.
|
|
|
|
// Calling services while attached is never a good idea.
|
|
// However, MmMapUserAddressesToPage handles this case, so we
|
|
// can attach and call:
|
|
|
|
KeAttachProcess(PsGetProcessPcb(peDirectDrawLocal->Process));
|
|
|
|
if (!(peMap->fl & DD_VMEMMAPPING_FLAG_AGP))
|
|
{
|
|
Status = MmMapUserAddressesToPage(
|
|
(VOID*) peMap->fpProcess, 0, gpDummyPage);
|
|
}
|
|
else
|
|
{
|
|
Status = AGPMapToDummy (peMap, peDirectDrawGlobal, gpDummyPage);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DDKHEAP(("MmMapUserAddressesToPage failed: %08X\n", Status));
|
|
}
|
|
|
|
KeDetachProcess();
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
EDD_SURFACE* peSurface;
|
|
|
|
WARNING("vDdUnreferenceVirtualMap: "
|
|
"failed to map user addresses to dummy page\n");
|
|
|
|
// Something went wrong so we must unmap the memory and remove
|
|
// any references to this map:
|
|
|
|
bUnmapMemory = TRUE;
|
|
|
|
// We need to traverse the surfaces of this local and mark all
|
|
// pointers to this mapping as NULL:
|
|
|
|
peSurface = peDirectDrawLocal->peSurface_Enum(NULL);
|
|
|
|
while (peSurface)
|
|
{
|
|
if (peSurface->peMap == peMap)
|
|
{
|
|
peSurface->peMap = NULL;
|
|
|
|
// Each mapping took a reference count on the surface's
|
|
// DirectDraw global, so undo that here:
|
|
|
|
vDdDecrementReferenceCount(
|
|
peSurface->peVirtualMapDdGlobal);
|
|
peSurface->peVirtualMapDdGlobal = NULL;
|
|
}
|
|
|
|
peSurface = peDirectDrawLocal->peSurface_Enum(peSurface);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
peMap->fl |= DD_VMEMMAPPING_FLAG_ALIASED;
|
|
gcDummyPageRefCnt++;
|
|
}
|
|
|
|
EngReleaseSemaphore(ghsemDummyPage);
|
|
}
|
|
|
|
if (bUnmapMemory)
|
|
{
|
|
if (!(peMap->fl & DD_VMEMMAPPING_FLAG_AGP))
|
|
{
|
|
vDdUnmapMemory(peMap, peDirectDrawGlobal, ProcessHandle);
|
|
}
|
|
else
|
|
{
|
|
vDdUnmapAgpHeap(peMap, peDirectDrawGlobal, peDirectDrawLocal);
|
|
}
|
|
|
|
EngAcquireSemaphore(ghsemDummyPage);
|
|
|
|
if (peMap->fl & DD_VMEMMAPPING_FLAG_ALIASED)
|
|
{
|
|
ASSERTGDI(gcDummyPageRefCnt > 0,
|
|
"Dummy page reference count will be < 0");
|
|
ASSERTGDI(gpDummyPage != NULL,
|
|
"Dereferencing dummy page which has not been allocated");
|
|
gcDummyPageRefCnt--;
|
|
}
|
|
|
|
if ((gpDummyPage != NULL) && (gcDummyPageRefCnt == 0))
|
|
{
|
|
ExFreePool(gpDummyPage);
|
|
gpDummyPage = NULL;
|
|
DDKHEAP(("Freed dummy page\n"));
|
|
}
|
|
|
|
EngReleaseSemaphore(ghsemDummyPage);
|
|
|
|
if (peMap->pAgpVirtualCommitMask != NULL)
|
|
{
|
|
VFREEMEM(peMap->pAgpVirtualCommitMask);
|
|
}
|
|
VFREEMEM(peMap);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DxDdEnableDirectDraw
|
|
*
|
|
* Allocates the global DirectDraw object and then enables the driver
|
|
* for DirectDraw.
|
|
*
|
|
* Assumes devlock already held.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
DxDdEnableDirectDraw(
|
|
HDEV hdev,
|
|
BOOL bEnableDriver
|
|
)
|
|
{
|
|
BOOL bRet = FALSE; // Assume failure
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
KEVENT* pAssertModeEvent;
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
// Don't bother doing anything for printers.
|
|
|
|
if (!po.bDisplayPDEV())
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
// Note that this must be zero initialized, because we promised
|
|
// the driver that we would. Don't zero-initialize the driver
|
|
// state, though, because there may be some open references to
|
|
// it!
|
|
|
|
peDirectDrawGlobal = po.peDirectDrawGlobal();
|
|
|
|
RtlZeroMemory((_DD_DIRECTDRAW_LOCAL*) peDirectDrawGlobal,
|
|
sizeof(_DD_DIRECTDRAW_LOCAL));
|
|
RtlZeroMemory((_DD_DIRECTDRAW_GLOBAL*) peDirectDrawGlobal,
|
|
sizeof(_DD_DIRECTDRAW_GLOBAL));
|
|
RtlZeroMemory((DD_DIRECTDRAW_GLOBAL_PDEV_DATA*) peDirectDrawGlobal,
|
|
sizeof(DD_DIRECTDRAW_GLOBAL_PDEV_DATA));
|
|
|
|
// Initialize our private structures:
|
|
|
|
peDirectDrawGlobal->hdev = po.hdev();
|
|
peDirectDrawGlobal->dhpdev = po.dhpdev();
|
|
peDirectDrawGlobal->bSuspended = FALSE;
|
|
|
|
// The VideoPort HAL calls oddly reference PDD_DIRECTDRAW_LOCAL
|
|
// instead of PDD_DIRECTDRAW_GLOBAL. The driver will never reference
|
|
// anything in the local structure other than 'lpGbl', so we simply
|
|
// add a DIRECTDRAW_LOCAL structure to the definition of the
|
|
// DIRECTDRAW_GLOBAL structure that points to itself:
|
|
|
|
peDirectDrawGlobal->lpGbl = peDirectDrawGlobal;
|
|
|
|
peDirectDrawGlobal->llAssertModeTimeout
|
|
= llDdAssertModeTimeout();
|
|
|
|
// The event must live in non-paged pool:
|
|
|
|
pAssertModeEvent = (KEVENT*) PALLOCNONPAGED(sizeof(KEVENT),'eddG');
|
|
|
|
if (pAssertModeEvent != NULL)
|
|
{
|
|
peDirectDrawGlobal->pAssertModeEvent = pAssertModeEvent;
|
|
|
|
KeInitializeEvent(pAssertModeEvent,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
if (bEnableDriver)
|
|
{
|
|
vDdEnableDriver(peDirectDrawGlobal);
|
|
}
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DxDdDisableDirectDraw
|
|
*
|
|
* Note: This function may be called without bDdEnableDirectDraw having
|
|
* first been called!
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
DxDdDisableDirectDraw(
|
|
HDEV hdev,
|
|
BOOL bDisableDriver
|
|
)
|
|
{
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
peDirectDrawGlobal = po.peDirectDrawGlobal();
|
|
|
|
// Don't bother doing anything more if we were never enabled in the
|
|
// first place.
|
|
|
|
if ((peDirectDrawGlobal == NULL) ||
|
|
(peDirectDrawGlobal->hdev == NULL))
|
|
{
|
|
return;
|
|
}
|
|
|
|
EDD_DEVLOCK eDevLock(hdev);
|
|
|
|
if (bDisableDriver)
|
|
{
|
|
vDdDisableDriver(peDirectDrawGlobal);
|
|
}
|
|
|
|
if (peDirectDrawGlobal->pAssertModeEvent != NULL)
|
|
{
|
|
VFREEMEM(peDirectDrawGlobal->pAssertModeEvent);
|
|
}
|
|
|
|
RtlZeroMemory(peDirectDrawGlobal, sizeof(*peDirectDrawGlobal));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdDisableDirectDrawObject
|
|
*
|
|
* Disables a DirectDraw object. This amounts to simply unmapping the
|
|
* view of the frame buffer.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdDisableDirectDrawObject(
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal
|
|
)
|
|
{
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE ProcessHandle;
|
|
CLIENT_ID ClientId;
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
BOOL bUnmapAgpHeaps;
|
|
|
|
bUnmapAgpHeaps = peDirectDrawLocal->iAgpHeapsMapped > 0;
|
|
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
// We may be in a different process from the one in which the
|
|
// memory was originally mapped. Consequently, we have to open
|
|
// a handle to the process in which the mapping was created.
|
|
// We are guaranteed that the process will still exist because
|
|
// this view is always unmapped at process termination.
|
|
|
|
ProcessHandle = NULL;
|
|
|
|
if (bUnmapAgpHeaps ||
|
|
((peDirectDrawLocal->fl & DD_LOCAL_FLAG_MEMORY_MAPPED) &&
|
|
(peDirectDrawGlobal->CallBacks.dwFlags & DDHAL_CB32_MAPMEMORY)))
|
|
{
|
|
ClientId.UniqueThread = (HANDLE) NULL;
|
|
ClientId.UniqueProcess = peDirectDrawLocal->UniqueProcess;
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
NULL,
|
|
OBJ_INHERIT | OBJ_KERNEL_HANDLE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = ZwOpenProcess(&ProcessHandle,
|
|
PROCESS_DUP_HANDLE,
|
|
&ObjectAttributes,
|
|
&ClientId);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
WARNING("vDdDisableDirectDrawObject: "
|
|
"Couldn't open process handle");
|
|
ProcessHandle = NULL;
|
|
}
|
|
}
|
|
|
|
if (peDirectDrawLocal->fl & DD_LOCAL_FLAG_MEMORY_MAPPED)
|
|
{
|
|
peDirectDrawLocal->fl &= ~DD_LOCAL_FLAG_MEMORY_MAPPED;
|
|
peDirectDrawGlobal->cMaps--;
|
|
|
|
ASSERTGDI(peDirectDrawGlobal->cMaps >= 0, "Invalid map count");
|
|
|
|
if ((peDirectDrawGlobal->CallBacks.dwFlags & DDHAL_CB32_MAPMEMORY) &&
|
|
ProcessHandle != NULL)
|
|
{
|
|
vDdUnreferenceVirtualMap(peDirectDrawLocal->peMapCurrent,
|
|
peDirectDrawGlobal,
|
|
peDirectDrawLocal,
|
|
ProcessHandle,
|
|
TRUE);
|
|
|
|
peDirectDrawLocal->peMapCurrent = NULL;
|
|
}
|
|
}
|
|
|
|
// Unmap AGP heaps if necessary:
|
|
|
|
if (bUnmapAgpHeaps && (ProcessHandle != NULL))
|
|
{
|
|
DWORD i;
|
|
EDD_VMEMMAPPING** ppeMapAgp;
|
|
|
|
ppeMapAgp = peDirectDrawLocal->ppeMapAgp;
|
|
|
|
for (i = 0; i < peDirectDrawGlobal->dwNumHeaps; i++, ppeMapAgp++)
|
|
{
|
|
if (*ppeMapAgp != NULL)
|
|
{
|
|
vDdUnreferenceVirtualMap(*ppeMapAgp,
|
|
peDirectDrawGlobal,
|
|
peDirectDrawLocal,
|
|
ProcessHandle,
|
|
TRUE);
|
|
|
|
*ppeMapAgp = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ProcessHandle != NULL)
|
|
{
|
|
Status = ZwClose(ProcessHandle);
|
|
ASSERTGDI(NT_SUCCESS(Status), "Failed close handle");
|
|
}
|
|
|
|
// Stop any active videoports:
|
|
|
|
for (peVideoPort = peDirectDrawLocal->peVideoPort_DdList;
|
|
peVideoPort != NULL;
|
|
peVideoPort = peVideoPort->peVideoPort_DdNext)
|
|
{
|
|
vDdStopVideoPort(peVideoPort);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HANDLE hDdCreateDirectDrawLocal
|
|
*
|
|
* Creates a new local DirectDraw object for a process attaching to
|
|
* a PDEV for which we've already enabled DirectDraw. Note that the
|
|
* DirectDraw user-mode process will actually think of this as its
|
|
* 'global' DirectDraw object.
|
|
*
|
|
* Assumes devlock already held.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HANDLE
|
|
hDdCreateDirectDrawLocal(
|
|
PDEVOBJ& po
|
|
)
|
|
{
|
|
HANDLE h;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_VMEMMAPPING** ppeMapAgp;
|
|
|
|
h = 0;
|
|
|
|
peDirectDrawGlobal = po.peDirectDrawGlobal();
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
if (peDirectDrawGlobal->dwNumHeaps > 0)
|
|
{
|
|
// Allocate an array to hold per-process AGP heap information.
|
|
ppeMapAgp = (EDD_VMEMMAPPING**)
|
|
PALLOCMEM(sizeof(EDD_VMEMMAPPING*) *
|
|
peDirectDrawGlobal->dwNumHeaps,
|
|
'pddG');
|
|
if (ppeMapAgp == NULL)
|
|
{
|
|
return h;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ppeMapAgp = NULL;
|
|
}
|
|
|
|
// We allocate this via the handle manager so that we can use the
|
|
// existing handle manager process clean-up mechanisms:
|
|
|
|
|
|
peDirectDrawLocal = (EDD_DIRECTDRAW_LOCAL*) DdHmgAlloc(
|
|
sizeof(EDD_DIRECTDRAW_LOCAL),
|
|
DD_DIRECTDRAW_TYPE,
|
|
HMGR_ALLOC_LOCK);
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
// Insert this object at the head of the object list:
|
|
|
|
peDirectDrawLocal->peDirectDrawLocalNext
|
|
= peDirectDrawGlobal->peDirectDrawLocalList;
|
|
|
|
peDirectDrawGlobal->peDirectDrawLocalList = peDirectDrawLocal;
|
|
|
|
// Initialize surface list:
|
|
|
|
InitializeListHead(&(peDirectDrawLocal->ListHead_eSurface));
|
|
|
|
// Initialize private GDI data:
|
|
|
|
peDirectDrawLocal->peDirectDrawGlobal = peDirectDrawGlobal;
|
|
peDirectDrawLocal->lpGbl = peDirectDrawGlobal;
|
|
peDirectDrawLocal->UniqueProcess = PsGetCurrentThreadProcessId();
|
|
peDirectDrawLocal->Process = PsGetCurrentProcess();
|
|
|
|
peDirectDrawLocal->ppeMapAgp = ppeMapAgp;
|
|
|
|
peDirectDrawLocal->peMapCurrent = NULL;
|
|
|
|
// This has reference to PDEVOBJ, so increment ref count of PDEVOBJ:
|
|
|
|
po.vReferencePdev();
|
|
|
|
// Do an HmgUnlock:
|
|
|
|
h = peDirectDrawLocal->hHmgr;
|
|
DEC_EXCLUSIVE_REF_CNT(peDirectDrawLocal);
|
|
|
|
// Setup the AGP heaps if the driver exposes any
|
|
|
|
MapAllAgpHeaps( peDirectDrawLocal );
|
|
}
|
|
else if (ppeMapAgp != NULL)
|
|
{
|
|
VFREEMEM(ppeMapAgp);
|
|
}
|
|
|
|
return(h);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdDeleteDirectDrawObject
|
|
*
|
|
* Deletes a kernel-mode representation of the DirectDraw object.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdDeleteDirectDrawObject(
|
|
HANDLE hDirectDrawLocal,
|
|
BOOL bProcessTermination
|
|
)
|
|
{
|
|
BOOL bRet;
|
|
BOOL b;
|
|
VOID* pRemove;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_DIRECTDRAW_LOCAL* peTmp;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_VIDEOPORT* peVideoPort;
|
|
EDD_VIDEOPORT* peVideoPortNext;
|
|
EDD_MOTIONCOMP* peMotionComp;
|
|
EDD_MOTIONCOMP* peMotionCompNext;
|
|
EDD_SURFACE* peSurface;
|
|
EDD_SURFACE* peSurfaceNext;
|
|
|
|
bRet = FALSE;
|
|
|
|
peDirectDrawLocal = (EDD_DIRECTDRAW_LOCAL*)
|
|
DdHmgLock((HDD_OBJ) hDirectDrawLocal, DD_DIRECTDRAW_TYPE, FALSE);
|
|
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
b = TRUE;
|
|
|
|
// Now, try to delete all videoports associated with this object:
|
|
|
|
for (peVideoPort = peDirectDrawLocal->peVideoPort_DdList;
|
|
peVideoPort != NULL;
|
|
peVideoPort = peVideoPortNext)
|
|
{
|
|
// Don't reference peVideoPort after it's been deleted!
|
|
|
|
peVideoPortNext = peVideoPort->peVideoPort_DdNext;
|
|
b &= bDdDeleteVideoPortObject(peVideoPort->hGet(), NULL);
|
|
}
|
|
|
|
for (peMotionComp = peDirectDrawLocal->peMotionComp_DdList;
|
|
peMotionComp != NULL;
|
|
peMotionComp = peMotionCompNext)
|
|
{
|
|
peMotionCompNext = peMotionComp->peMotionComp_DdNext;
|
|
b &= bDdDeleteMotionCompObject(peMotionComp->hGet(), NULL);
|
|
}
|
|
|
|
// Next, try to delete all surfaces associated with this object:
|
|
|
|
peSurface = peDirectDrawLocal->peSurface_Enum(NULL);
|
|
|
|
while (peSurface)
|
|
{
|
|
// Don't reference peSurface after it's been deleted!
|
|
|
|
peSurfaceNext = peDirectDrawLocal->peSurface_Enum(peSurface);
|
|
|
|
// Delete the surface
|
|
|
|
b &= bDdDeleteSurfaceObject(peSurface->hGet(), NULL);
|
|
|
|
// Move onto next one
|
|
|
|
peSurface = peSurfaceNext;
|
|
}
|
|
|
|
{
|
|
EDD_SHAREDEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
// If they set a gamma ramp, restore it now
|
|
|
|
if (peDirectDrawLocal->pGammaRamp != NULL)
|
|
{
|
|
DxEngSetDeviceGammaRamp(
|
|
po.hdev(),
|
|
peDirectDrawLocal->pGammaRamp,
|
|
TRUE);
|
|
VFREEMEM(peDirectDrawLocal->pGammaRamp);
|
|
peDirectDrawLocal->pGammaRamp = NULL;
|
|
}
|
|
|
|
if (peDirectDrawGlobal->Miscellaneous2CallBacks.DestroyDDLocal)
|
|
{
|
|
DWORD dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
DD_DESTROYDDLOCALDATA destDDLcl;
|
|
destDDLcl.dwFlags = 0;
|
|
destDDLcl.pDDLcl = peDirectDrawLocal;
|
|
dwRet = peDirectDrawGlobal->Miscellaneous2CallBacks.DestroyDDLocal(&destDDLcl);
|
|
if (dwRet == DDHAL_DRIVER_NOTHANDLED)
|
|
{
|
|
WARNING("bDdDeleteDirectDrawObject: failed DestroyDDLocal\n");
|
|
}
|
|
}
|
|
|
|
// Only delete the DirectDraw object if we successfully deleted
|
|
// all linked surface objects:
|
|
|
|
if (b)
|
|
{
|
|
DWORD dwHeap;
|
|
LPVIDMEM pHeap;
|
|
|
|
// Remove object from the handle manager:
|
|
|
|
pRemove = DdHmgRemoveObject((HDD_OBJ) hDirectDrawLocal,
|
|
1,
|
|
0,
|
|
TRUE,
|
|
DD_DIRECTDRAW_TYPE);
|
|
|
|
ASSERTGDI(pRemove != NULL, "Couldn't delete DirectDraw object");
|
|
|
|
vDdDisableDirectDrawObject(peDirectDrawLocal);
|
|
|
|
// Now that we've cleanup up the surfaces, now we will cleanup any
|
|
// agp commits that need to be.
|
|
|
|
pHeap = peDirectDrawGlobal->pvmList;
|
|
for (dwHeap = 0;
|
|
dwHeap < peDirectDrawGlobal->dwNumHeaps;
|
|
pHeap++, dwHeap++)
|
|
{
|
|
if (!(pHeap->dwFlags & VIDMEM_ISHEAP) &&
|
|
!(pHeap->dwFlags & VIDMEM_HEAPDISABLED) &&
|
|
(pHeap->dwFlags & VIDMEM_ISNONLOCAL) &&
|
|
(pHeap->lpHeap != NULL))
|
|
{
|
|
CleanupAgpCommits( pHeap, pHeap->lpHeap->hdevAGP,
|
|
peDirectDrawGlobal, dwHeap );
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Remove the global DirectDraw object from the PDEV when
|
|
// the last associated local object is destroyed, and
|
|
// call the driver:
|
|
|
|
if (peDirectDrawGlobal->peDirectDrawLocalList == peDirectDrawLocal)
|
|
{
|
|
peDirectDrawGlobal->peDirectDrawLocalList
|
|
= peDirectDrawLocal->peDirectDrawLocalNext;
|
|
}
|
|
else
|
|
{
|
|
for (peTmp = peDirectDrawGlobal->peDirectDrawLocalList;
|
|
peTmp->peDirectDrawLocalNext != peDirectDrawLocal;
|
|
peTmp = peTmp->peDirectDrawLocalNext)
|
|
;
|
|
|
|
peTmp->peDirectDrawLocalNext
|
|
= peDirectDrawLocal->peDirectDrawLocalNext;
|
|
}
|
|
|
|
// We're all done with this object, so free the memory and
|
|
// leave:
|
|
|
|
if (peDirectDrawLocal->ppeMapAgp != NULL)
|
|
{
|
|
VFREEMEM(peDirectDrawLocal->ppeMapAgp);
|
|
}
|
|
|
|
DdFreeObject(peDirectDrawLocal, DD_DIRECTDRAW_TYPE);
|
|
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("bDdDeleteDirectDrawObject: A surface was busy\n");
|
|
if (bProcessTermination)
|
|
{
|
|
peDirectDrawLocal->fl |= DD_LOCAL_DISABLED;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bRet)
|
|
{
|
|
// Unreference PDEVOBJ - must not have devlock
|
|
po.vUnreferencePdev();
|
|
}
|
|
|
|
// Note that we can't force a repaint here by calling
|
|
// UserRedrawDesktop because we may be in a bad process context.
|
|
}
|
|
else
|
|
{
|
|
WARNING("bDdDeleteDirectDrawObject: Bad handle or object busy\n");
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdRelinquishSurfaceOrBufferLock
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdRelinquishSurfaceOrBufferLock(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
DD_UNLOCKDATA UnlockData;
|
|
EDD_SURFACE* peTmp;
|
|
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
ASSERTGDI(peSurface->cLocks > 0, "Must have non-zero locks to relinquish");
|
|
|
|
if (peSurface->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER)
|
|
{
|
|
if (peDirectDrawGlobal->D3dBufCallbacks.UnlockD3DBuffer != NULL)
|
|
{
|
|
UnlockData.lpDD = peDirectDrawGlobal;
|
|
UnlockData.lpDDSurface = peSurface;
|
|
|
|
peDirectDrawGlobal->D3dBufCallbacks.UnlockD3DBuffer(&UnlockData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags &
|
|
DDHAL_SURFCB32_UNLOCK)
|
|
{
|
|
UnlockData.lpDD = peDirectDrawGlobal;
|
|
UnlockData.lpDDSurface = peSurface;
|
|
|
|
peDirectDrawGlobal->SurfaceCallBacks.Unlock(&UnlockData);
|
|
}
|
|
}
|
|
|
|
// An application may take multiple locks on the same surface:
|
|
|
|
if (--peSurface->cLocks == 0)
|
|
{
|
|
if (!(peSurface->dwFlags & DDRAWISURF_DRIVERMANAGED) ||
|
|
((peSurface->dwFlags & DDRAWISURF_DRIVERMANAGED) &&
|
|
(peSurface->ddsCapsEx.dwCaps2 & DDSCAPS2_DONOTPERSIST)))
|
|
{
|
|
peDirectDrawGlobal->cSurfaceLocks--;
|
|
}
|
|
|
|
if (peSurface->peMap ||
|
|
(peSurface->fl & DD_SURFACE_FLAG_FAKE_ALIAS_LOCK))
|
|
{
|
|
peDirectDrawGlobal->cSurfaceAliasedLocks--;
|
|
peSurface->fl &= ~DD_SURFACE_FLAG_FAKE_ALIAS_LOCK;
|
|
}
|
|
|
|
// Primary surface unlocks require special handling for stuff like
|
|
// pointer exclusion:
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_PRIMARY)
|
|
{
|
|
// Since all locks for this surface have been relinquished, remove
|
|
// it from the locked surface list.
|
|
|
|
if (peDirectDrawGlobal->peSurface_PrimaryLockList == peSurface)
|
|
{
|
|
peDirectDrawGlobal->peSurface_PrimaryLockList
|
|
= peSurface->peSurface_PrimaryLockNext;
|
|
}
|
|
else
|
|
{
|
|
for (peTmp = peDirectDrawGlobal->peSurface_PrimaryLockList;
|
|
peTmp->peSurface_PrimaryLockNext != peSurface;
|
|
peTmp = peTmp->peSurface_PrimaryLockNext)
|
|
{
|
|
ASSERTGDI(peTmp != NULL, "Can't find surface in lock list");
|
|
}
|
|
|
|
peTmp->peSurface_PrimaryLockNext
|
|
= peSurface->peSurface_PrimaryLockNext;
|
|
}
|
|
|
|
peSurface->peSurface_PrimaryLockNext = NULL;
|
|
|
|
// Redraw any sprites:
|
|
|
|
DxEngSpUnTearDownSprites(peDirectDrawGlobal->hdev,
|
|
&peSurface->rclLock,
|
|
TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdLooseManagedSurfaceObject
|
|
*
|
|
* Informs the driver that it should clean up any video memory allocated for
|
|
* a persistent managed surface since a mode switch has occured.
|
|
*
|
|
* 13-May-1999 -by- Sameer Nene [snene]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdLooseManagedSurfaceObject(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
EDD_SURFACE* peSurface,
|
|
DWORD* pdwRet // For returning driver return code,
|
|
) // may be NULL
|
|
{
|
|
DD_DESTROYSURFACEDATA DestroySurfaceData;
|
|
|
|
DD_ASSERTSHAREDEVLOCK();
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
DDKHEAP(("DDKHEAP: Loosing surface %X (%X)\n",
|
|
peSurface->hGet(), peSurface));
|
|
|
|
// Due to video mode change, this driver managed surface is lives in "different" video
|
|
// driver then what the driver actually "manage" this surface.
|
|
// So we don't do anything here, since it has been "loose" already since mode change happened.
|
|
|
|
if (!(peSurface->fl & DD_SURFACE_FLAG_WRONG_DRIVER))
|
|
{
|
|
DestroySurfaceData.lpDD = peDirectDrawGlobal;
|
|
DestroySurfaceData.lpDDSurface = peSurface;
|
|
DestroySurfaceData.lpDDSurface->dwFlags |= DDRAWISURF_INVALID;
|
|
if ((peSurface->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER) &&
|
|
peDirectDrawGlobal->D3dBufCallbacks.DestroyD3DBuffer != NULL)
|
|
{
|
|
peDirectDrawGlobal->D3dBufCallbacks.DestroyD3DBuffer(&DestroySurfaceData);
|
|
}
|
|
else if (!(peSurface->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER) &&
|
|
(peDirectDrawGlobal->SurfaceCallBacks.dwFlags & DDHAL_SURFCB32_DESTROYSURFACE))
|
|
{
|
|
peDirectDrawGlobal->SurfaceCallBacks.DestroySurface(&DestroySurfaceData);
|
|
}
|
|
DestroySurfaceData.lpDDSurface->dwFlags &= ~DDRAWISURF_INVALID;
|
|
}
|
|
else
|
|
{
|
|
// WARNING("vDdLooseManagedSurfaceObject: called with DD_SURFACE_FLAG_WRONG_DRIVER");
|
|
}
|
|
|
|
if (pdwRet != NULL)
|
|
{
|
|
*pdwRet = DDHAL_DRIVER_HANDLED;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID SafeFreeUserMem
|
|
*
|
|
* Frees user mem and switches to the correct process if required.
|
|
*
|
|
* 5-Apr-2001 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
SafeFreeUserMem(
|
|
PVOID pv,
|
|
PEPROCESS Process
|
|
)
|
|
{
|
|
if (PsGetCurrentProcess() == Process)
|
|
{
|
|
EngFreeUserMem(pv);
|
|
}
|
|
else
|
|
{
|
|
// Calling services while attached is never a good idea. However,
|
|
// free virtual memory handles this case, so we can attach and
|
|
// call.
|
|
//
|
|
// Note that the process must exist. We are guaranteed that this
|
|
// is the case because we automatically delete all surfaces on
|
|
// process deletion.
|
|
|
|
KeAttachProcess(PsGetProcessPcb(Process));
|
|
EngFreeUserMem(pv);
|
|
KeDetachProcess();
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DeferMemoryFree
|
|
*
|
|
* Places the memory into a list to be freed at a later time when it's safe.
|
|
*
|
|
* 5-Apr-2001 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
DeferMemoryFree(
|
|
PVOID pv,
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
DD_USERMEM_DEFER* pDefer;
|
|
|
|
pDefer = (DD_USERMEM_DEFER*) PALLOCMEM(sizeof(DD_USERMEM_DEFER),
|
|
'pddG');
|
|
if (pDefer != NULL)
|
|
{
|
|
pDefer->pUserMem = pv;
|
|
pDefer->peSurface = peSurface;
|
|
pDefer->pNext = peSurface->peDirectDrawLocal->peDirectDrawGlobal->pUserMemDefer;
|
|
peSurface->peDirectDrawLocal->peDirectDrawGlobal->pUserMemDefer = pDefer;
|
|
peSurface->fl |= DD_SURFACE_FLAG_DEFER_USERMEM;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdDisableSurfaceObject
|
|
*
|
|
* Disables a kernel-mode representation of the surface. This is also
|
|
* known as marking the surface as 'lost'.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdDisableSurfaceObject(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
EDD_SURFACE* peSurface,
|
|
DWORD* pdwRet // For returning driver return code,
|
|
) // may be NULL
|
|
{
|
|
DWORD dwRet;
|
|
DXOBJ* pDxObj;
|
|
DXOBJ* pDxObjNext;
|
|
DD_FLIPDATA FlipData;
|
|
EDD_SURFACE* peSurfaceCurrent;
|
|
EDD_SURFACE* peSurfacePrimary;
|
|
DD_DESTROYSURFACEDATA DestroySurfaceData;
|
|
DD_UPDATEOVERLAYDATA UpdateOverlayData;
|
|
|
|
DD_ASSERTSHAREDEVLOCK();
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
DDKHEAP(("DDKHEAP: Disabling surface %X (%X)\n",
|
|
peSurface->hGet(), peSurface));
|
|
|
|
// If this surface is a destination surface for the videoport, turn it
|
|
// off:
|
|
|
|
if (peSurface->lpVideoPort != NULL)
|
|
{
|
|
vDdStopVideoPort(pedFromLp(peSurface->lpVideoPort));
|
|
|
|
ASSERTGDI(peSurface->lpVideoPort == NULL, "Expected surface clean-up");
|
|
}
|
|
|
|
// Mark the DXAPI instance of the surface as lost:
|
|
|
|
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 );
|
|
}
|
|
|
|
if (peSurface->peDxSurface != NULL)
|
|
{
|
|
peDirectDrawGlobal->pfnLoseObject(peSurface->peDxSurface,
|
|
LO_SURFACE);
|
|
}
|
|
|
|
if (peSurface->hbmGdi != NULL)
|
|
{
|
|
// It's not always possible to delete the cached GDI
|
|
// bitmap here, because we might have to first un-select
|
|
// the bitmap from its DC, and doing so requires an
|
|
// exclusive lock on the DC, which may not be possible
|
|
// if another thread is currently in kernel mode with the
|
|
// DC locked, just waiting for us to release the devlock.
|
|
//
|
|
// But we desperately need to delete the driver's
|
|
// realization at this point, before a mode change happens
|
|
// which renders its associations invalid. So we do that
|
|
// now.
|
|
//
|
|
// This may leave the surface in an unusable state (which
|
|
// is true even for non-DrvDeriveSurface surfaces).
|
|
// That's okay, because the surface can't be selected into
|
|
// any other DC, and the DC is marked as 'disabled' in the
|
|
// following snibbet of code.
|
|
|
|
// Bug 330141 : sr(hbmGdi) does not work since it fails
|
|
// when we are called on a non-creating thread in mode
|
|
// change, thus not deleting the bitmap.
|
|
|
|
SURFOBJ* pso;
|
|
|
|
if ((pso = DxEngAltLockSurface(peSurface->hbmGdi)) != NULL)
|
|
{
|
|
if (pso->dhsurf != NULL)
|
|
{
|
|
(*PPFNDRV(po, DeleteDeviceBitmap))(pso->dhsurf);
|
|
pso->dhsurf = NULL;
|
|
}
|
|
|
|
EngUnlockSurface(pso);
|
|
}
|
|
}
|
|
|
|
if (peSurface->hdc != NULL)
|
|
{
|
|
// We've given out a DC to the application via GetDC that
|
|
// allows it to have GDI draw directly on the surface.
|
|
// The problem is that we want to unmap the application's
|
|
// view of the frame buffer -- but now we can have GDI
|
|
// drawing to it. So if we simply forced the unmap, GDI
|
|
// would access violate if the DC was ever used again.
|
|
//
|
|
// We also can't simply delete the DC, because there may
|
|
// be another thread already in kernel mode that has locked
|
|
// the DC and is waiting on the devlock -- which we have.
|
|
//
|
|
// Note that the DC can not simply be deleted here, because
|
|
// it may validly be in-use by another thread that has made
|
|
// it to the kernel. The DC deletion has to wait until
|
|
// bDdDeleteSurfaceObject.
|
|
|
|
if (!DxEngSetDCState(peSurface->hdc,DCSTATE_FULLSCREEN,(ULONG_PTR)TRUE))
|
|
{
|
|
WARNING("vDdDisableSurfaceObject: Couldn't mark DC as disabled.\n");
|
|
ghdcCantLose = peSurface->hdc;
|
|
#if DBG_HIDEYUKN
|
|
DbgBreakPoint();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
// System-memory surfaces should only ever need to be disabled from
|
|
// the same process in which they were created:
|
|
|
|
if (peSurface->hSecure)
|
|
{
|
|
ASSERTGDI(peSurface->peDirectDrawLocal->Process
|
|
== PsGetCurrentProcess(),
|
|
"vDdDisableSurfaceObject: SYSMEM object disabled in wrong process");
|
|
|
|
MmUnsecureVirtualMemory(peSurface->hSecure);
|
|
|
|
peSurface->hSecure = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (peSurface->cLocks != 0)
|
|
{
|
|
// We're unmapping the frame buffer view while there are outstanding
|
|
// frame buffer locks; keep track of the address for debugging
|
|
// purposes, since the application is undoubtedly about to access-
|
|
// violate:
|
|
|
|
gfpUnmap = peSurface->peDirectDrawLocal->fpProcess;
|
|
|
|
#if DBG
|
|
DbgPrint("GDI vDdDisableSurfaceObject: Preemptively unmapping application's\n");
|
|
DbgPrint(" frame buffer view at 0x%lx!\n\n", gfpUnmap);
|
|
#endif
|
|
}
|
|
|
|
// Remove any outstanding locks and repaint the mouse pointer:
|
|
|
|
while (peSurface->cLocks != 0)
|
|
{
|
|
vDdRelinquishSurfaceOrBufferLock(peDirectDrawGlobal, peSurface);
|
|
}
|
|
|
|
// If this surface is the currently visible one as a result of a flip,
|
|
// then switch back to the primary GDI surface:
|
|
|
|
peSurfaceCurrent = peDirectDrawGlobal->peSurfaceCurrent;
|
|
peSurfacePrimary = peDirectDrawGlobal->peSurfacePrimary;
|
|
|
|
if ((peSurfaceCurrent == peSurface) || (peSurfacePrimary == peSurface))
|
|
{
|
|
// We may be in a different process from the one that created the
|
|
// surface, so don't flip to the primary if it's a user-memory
|
|
// allocated surface:
|
|
|
|
if ((peSurfacePrimary != NULL) &&
|
|
!(peSurfacePrimary->fl & DD_SURFACE_FLAG_UMEM_ALLOCATED))
|
|
{
|
|
ASSERTGDI((peSurfaceCurrent != NULL) && (peSurfacePrimary != NULL),
|
|
"Both surfaces must be non-NULL");
|
|
ASSERTGDI(peSurfacePrimary->fl & DD_SURFACE_FLAG_PRIMARY,
|
|
"Primary flag is confused.");
|
|
|
|
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags & DDHAL_SURFCB32_FLIP)
|
|
{
|
|
// If the current isn't the primary, then swap back to the primary:
|
|
|
|
if (!(peSurfaceCurrent->fl & DD_SURFACE_FLAG_PRIMARY))
|
|
{
|
|
FlipData.ddRVal = DDERR_GENERIC;
|
|
FlipData.lpDD = peDirectDrawGlobal;
|
|
FlipData.lpSurfCurr = peSurfaceCurrent;
|
|
FlipData.lpSurfTarg = peSurfacePrimary;
|
|
FlipData.dwFlags = 0;
|
|
FlipData.lpSurfCurrLeft = NULL;
|
|
FlipData.lpSurfTargLeft = NULL;
|
|
|
|
peSurfacePrimary->ddsCaps.dwCaps |= DDSCAPS_PRIMARYSURFACE;
|
|
|
|
do {
|
|
dwRet = peDirectDrawGlobal->SurfaceCallBacks.Flip(&FlipData);
|
|
|
|
} while ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(FlipData.ddRVal == DDERR_WASSTILLDRAWING));
|
|
|
|
ASSERTGDI((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(FlipData.ddRVal == DD_OK),
|
|
"Driver failed when cleaning up flip surfaces");
|
|
}
|
|
}
|
|
}
|
|
|
|
peDirectDrawGlobal->peSurfaceCurrent = NULL;
|
|
peDirectDrawGlobal->peSurfacePrimary = NULL;
|
|
}
|
|
|
|
// Make sure the overlay is marked as hidden before it's deleted, so
|
|
// that we don't have to rely on drivers doing it in their DestroySurface
|
|
// routine:
|
|
|
|
if ((peSurface->ddsCaps.dwCaps & DDSCAPS_OVERLAY) &&
|
|
(peDirectDrawGlobal->SurfaceCallBacks.dwFlags &
|
|
DDHAL_SURFCB32_UPDATEOVERLAY) &&
|
|
(peSurface->fl & DD_SURFACE_FLAG_UPDATE_OVERLAY_CALLED))
|
|
{
|
|
UpdateOverlayData.lpDD = peDirectDrawGlobal;
|
|
UpdateOverlayData.lpDDDestSurface = NULL;
|
|
UpdateOverlayData.lpDDSrcSurface = peSurface;
|
|
UpdateOverlayData.dwFlags = DDOVER_HIDE;
|
|
UpdateOverlayData.ddRVal = DDERR_GENERIC;
|
|
|
|
peDirectDrawGlobal->SurfaceCallBacks.UpdateOverlay(&UpdateOverlayData);
|
|
}
|
|
|
|
// If we allocated user-mode memory on the driver's behalf, we'll
|
|
// free it now. This is complicated by the fact that we may be
|
|
// in a different process context.
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_UMEM_ALLOCATED)
|
|
{
|
|
ASSERTGDI(peSurface->fpVidMem != NULL, "Expected non-NULL fpVidMem");
|
|
|
|
DDKHEAP(("DDKHEAP: Fre um %08X, surf %X (%X)\n",
|
|
peSurface->fpVidMem, peSurface->hGet(), peSurface));
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_ALIAS_LOCK)
|
|
{
|
|
DeferMemoryFree((PVOID)peSurface->fpVidMem, peSurface);
|
|
}
|
|
else
|
|
{
|
|
SafeFreeUserMem((PVOID)peSurface->fpVidMem, peSurface->peDirectDrawLocal->Process);
|
|
}
|
|
peSurface->fpVidMem = 0;
|
|
}
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_VMEM_ALLOCATED)
|
|
{
|
|
ASSERTGDI(peSurface->lpVidMemHeap != NULL &&
|
|
peSurface->lpVidMemHeap->lpHeap &&
|
|
peSurface->fpHeapOffset != NULL,
|
|
"Expected non-NULL lpVidMemHeap and fpHeapOffset");
|
|
|
|
DDKHEAP(("DDKHEAP: Fre vm %08X, o %08X, heap %X, surf %X (%X)\n",
|
|
peSurface->fpVidMem, peSurface->fpHeapOffset,
|
|
peSurface->lpVidMemHeap->lpHeap,
|
|
peSurface->hGet(), peSurface));
|
|
|
|
DxDdHeapVidMemFree(peSurface->lpVidMemHeap->lpHeap,
|
|
peSurface->fpHeapOffset);
|
|
|
|
peSurface->lpVidMemHeap = NULL;
|
|
peSurface->fpVidMem = 0;
|
|
peSurface->fpHeapOffset = 0;
|
|
}
|
|
|
|
// Delete the driver's surface instance. Note that we may be calling
|
|
// here from a process different from the one in which the surface was
|
|
// created, meaning that the driver cannot make function calls like
|
|
// EngFreeUserMem.
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_DRIVER_CREATED)
|
|
{
|
|
EDD_DIRECTDRAW_GLOBAL *peDdGlobalDriver;
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_WRONG_DRIVER)
|
|
{
|
|
WARNING("vDdDisableSurfaceObject: Call driver other than current.");
|
|
|
|
peDdGlobalDriver = peSurface->peDdGlobalCreator;
|
|
}
|
|
else
|
|
{
|
|
peDdGlobalDriver = peSurface->peDirectDrawGlobal;
|
|
}
|
|
|
|
DestroySurfaceData.lpDD = peDdGlobalDriver;
|
|
DestroySurfaceData.lpDDSurface = peSurface;
|
|
|
|
if ((peSurface->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER) &&
|
|
peDdGlobalDriver->D3dBufCallbacks.DestroyD3DBuffer != NULL)
|
|
{
|
|
dwRet = peDdGlobalDriver->
|
|
D3dBufCallbacks.DestroyD3DBuffer(&DestroySurfaceData);
|
|
}
|
|
else if (!(peSurface->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER) &&
|
|
(peDdGlobalDriver->SurfaceCallBacks.dwFlags &
|
|
DDHAL_SURFCB32_DESTROYSURFACE))
|
|
{
|
|
dwRet = peDdGlobalDriver->
|
|
SurfaceCallBacks.DestroySurface(&DestroySurfaceData);
|
|
}
|
|
|
|
// Drivers are supposed to return DDHAL_DRIVER_NOTHANDLED from
|
|
// DestroySurface if they returned DDHAL_DRIVER_NOTHANDLED from
|
|
// CreateSurface, which is the case for PLEASEALLOC_*. We
|
|
// munged the return code for PLEASEALLOC_* at CreateSurface
|
|
// time; we have to munge it now, too:
|
|
|
|
if ((dwRet == DDHAL_DRIVER_NOTHANDLED) &&
|
|
(peSurface->fl & (DD_SURFACE_FLAG_UMEM_ALLOCATED |
|
|
DD_SURFACE_FLAG_VMEM_ALLOCATED)))
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
}
|
|
|
|
// Decrement ref count on driver if driver managed surface.
|
|
|
|
if (peSurface->dwFlags & DDRAWISURF_DRIVERMANAGED)
|
|
{
|
|
ASSERTGDI(peSurface->fl & DD_SURFACE_FLAG_CREATE_COMPLETE,
|
|
"vDdDisableSurfaceObject: missing complete flag.");
|
|
|
|
vDdDecrementReferenceCount(peDdGlobalDriver);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mark the surface as lost and reset some flags now for if the
|
|
// surface gets reused:
|
|
|
|
if (!(peSurface->bLost))
|
|
{
|
|
peSurface->bLost = TRUE;
|
|
|
|
// If this surface is not lost formerly, but just lost here
|
|
// decrement active surface ref. count.
|
|
|
|
ASSERTGDI(peSurface->peDirectDrawLocal->cActiveSurface > 0,
|
|
"cActiveSurface will be negative");
|
|
|
|
peSurface->peDirectDrawLocal->cActiveSurface--;
|
|
}
|
|
|
|
// We used to zero the flags, but we need DD_SURFACE_FLAG_DEFER_USERMEM
|
|
// to survive until we call DeleteSurfaceObject.
|
|
peSurface->fl &= DD_SURFACE_FLAG_DEFER_USERMEM;
|
|
|
|
if (pdwRet != NULL)
|
|
{
|
|
*pdwRet = dwRet;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* EDD_SURFACE* peSurfaceFindAttachedMipMap
|
|
*
|
|
* Transmogrified from misc.c's FindAttachedMipMap.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
inline
|
|
EDD_SURFACE*
|
|
peSurfaceFindAttachedMipMap(
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
DD_ATTACHLIST* pAttachList;
|
|
EDD_SURFACE* peSurfaceAttached;
|
|
|
|
for (pAttachList = peSurface->lpAttachList;
|
|
pAttachList != NULL;
|
|
pAttachList = pAttachList->lpLink)
|
|
{
|
|
peSurfaceAttached = pedFromLp(pAttachList->lpAttached);
|
|
if (peSurfaceAttached->ddsCaps.dwCaps & DDSCAPS_MIPMAP)
|
|
{
|
|
return(peSurfaceAttached);
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* EDD_SURFACE* peSurfaceFindParentMipMap
|
|
*
|
|
* Transmogrified from misc.c's FindParentMipMap.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
inline
|
|
EDD_SURFACE*
|
|
peSurfaceFindParentMipMap(
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
DD_ATTACHLIST* pAttachList;
|
|
EDD_SURFACE* peSurfaceAttached;
|
|
|
|
for (pAttachList = peSurface->lpAttachListFrom;
|
|
pAttachList != NULL;
|
|
pAttachList = pAttachList->lpLink)
|
|
{
|
|
peSurfaceAttached = pedFromLp(pAttachList->lpAttached);
|
|
if (peSurfaceAttached->ddsCaps.dwCaps & DDSCAPS_MIPMAP)
|
|
{
|
|
return(peSurfaceAttached);
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdUpdateMipMapCount
|
|
*
|
|
* Transmogrified from ddsatch.c's UpdateMipMapCount.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdUpdateMipMapCount(
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
EDD_SURFACE* peSurfaceParent;
|
|
DWORD dwLevels;
|
|
|
|
DD_ASSERTDEVLOCK(peSurface->peDirectDrawGlobal);
|
|
|
|
// Find the top most level mip-map in the chain:
|
|
|
|
peSurfaceParent = peSurface;
|
|
while (peSurfaceParent != NULL)
|
|
{
|
|
peSurface = peSurfaceParent;
|
|
peSurfaceParent = peSurfaceFindParentMipMap(peSurface);
|
|
}
|
|
peSurfaceParent = peSurface;
|
|
|
|
// We have the top-most level in the mip-map chain. Now count the
|
|
// levels in the chain:
|
|
|
|
dwLevels = 0;
|
|
while (peSurface != NULL)
|
|
{
|
|
dwLevels++;
|
|
peSurface = peSurfaceFindAttachedMipMap(peSurface);
|
|
}
|
|
|
|
// Now update all the levels with their new mip-map count:
|
|
|
|
peSurface = peSurfaceParent;
|
|
while (peSurface != NULL)
|
|
{
|
|
peSurface->dwMipMapCount = dwLevels;
|
|
dwLevels--;
|
|
peSurface = peSurfaceFindAttachedMipMap(peSurface);
|
|
}
|
|
|
|
ASSERTGDI(dwLevels == 0, "Unexpected ending surface count");
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdRemoveAttachedSurface
|
|
*
|
|
* Transmogrified from ddsatch.c's DeleteOneLink.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdRemoveAttachedSurface(
|
|
EDD_SURFACE* peSurface,
|
|
EDD_SURFACE* peSurfaceAttached
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
DD_ATTACHLIST* pAttachCurrent;
|
|
DD_ATTACHLIST* pAttachLast;
|
|
|
|
// See if specified surface is attached:
|
|
|
|
pAttachCurrent = peSurface->lpAttachList;
|
|
pAttachLast = NULL;
|
|
while (pAttachCurrent != NULL)
|
|
{
|
|
if (pAttachCurrent->lpAttached == peSurfaceAttached)
|
|
break;
|
|
|
|
pAttachLast = pAttachCurrent;
|
|
pAttachCurrent = pAttachCurrent->lpLink;
|
|
}
|
|
if (pAttachCurrent != NULL)
|
|
{
|
|
// Delete the attached-from link:
|
|
|
|
if (pAttachLast == NULL)
|
|
{
|
|
peSurface->lpAttachList = pAttachCurrent->lpLink;
|
|
}
|
|
else
|
|
{
|
|
pAttachLast->lpLink = pAttachCurrent->lpLink;
|
|
}
|
|
VFREEMEM(pAttachCurrent);
|
|
|
|
// Remove the attached-to link:
|
|
|
|
pAttachCurrent = peSurfaceAttached->lpAttachListFrom;
|
|
pAttachLast = NULL;
|
|
while (pAttachCurrent != NULL)
|
|
{
|
|
if (pAttachCurrent->lpAttached == peSurface)
|
|
break;
|
|
|
|
pAttachLast = pAttachCurrent;
|
|
pAttachCurrent = pAttachCurrent->lpLink;
|
|
}
|
|
|
|
// Delete the attached-to link:
|
|
|
|
if (pAttachLast == NULL)
|
|
{
|
|
peSurfaceAttached->lpAttachListFrom = pAttachCurrent->lpLink;
|
|
}
|
|
else
|
|
{
|
|
pAttachLast->lpLink = pAttachCurrent->lpLink;
|
|
}
|
|
VFREEMEM(pAttachCurrent);
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdDeleteReferringAttachments
|
|
*
|
|
* This surface is being deleted. Remove any attachments to or from other
|
|
* surfaces.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdDeleteReferringAttachments(
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
DD_ATTACHLIST* pAttachList;
|
|
EDD_SURFACE* peSurfaceAttachedTo;
|
|
EDD_SURFACE* peSurfaceAttachedFrom;
|
|
BOOL b;
|
|
|
|
while (peSurface->lpAttachList != NULL)
|
|
{
|
|
peSurfaceAttachedTo
|
|
= pedFromLp(peSurface->lpAttachList->lpAttached);
|
|
|
|
b = bDdRemoveAttachedSurface(peSurface, peSurfaceAttachedTo);
|
|
vDdUpdateMipMapCount(peSurfaceAttachedTo);
|
|
|
|
ASSERTGDI(b, "Unexpected bDdRemoveAttachedSurface failure\n");
|
|
}
|
|
|
|
while (peSurface->lpAttachListFrom != NULL)
|
|
{
|
|
peSurfaceAttachedFrom
|
|
= pedFromLp(peSurface->lpAttachListFrom->lpAttached);
|
|
|
|
b = bDdRemoveAttachedSurface(peSurfaceAttachedFrom, peSurface);
|
|
vDdUpdateMipMapCount(peSurfaceAttachedFrom);
|
|
|
|
ASSERTGDI(b, "Unexpected bDdRemoveAttachedSurface failure\n");
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* void vDdReleaseVirtualMap
|
|
*
|
|
* Released the reference a surface has on a VMEMMAPPING structure
|
|
*
|
|
* 28-Oct-1998 -by- Anuj Gosalia [anujg]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void vDdReleaseVirtualMap(EDD_SURFACE* peSurface)
|
|
{
|
|
EDD_DIRECTDRAW_GLOBAL* peVirtualMapDdGlobal;
|
|
|
|
// Hold share to prevent video mode change.
|
|
{
|
|
EDD_SHARELOCK eShareLock(TRUE);
|
|
|
|
peVirtualMapDdGlobal = peSurface->peVirtualMapDdGlobal;
|
|
|
|
DDKHEAP(("vDdReleaseVirtualMap: peSurface=%lx, "
|
|
"peVirtualMapDdGlobal=%lx, peDirectDrawGlobal=%lx\n",
|
|
peSurface, peVirtualMapDdGlobal,
|
|
peSurface->peDirectDrawGlobal));
|
|
|
|
// See peVirtualMapDdGlobal is still present, since
|
|
// video mode change occured before locking share
|
|
// lock at above, this will be null by mode change thread.
|
|
|
|
if (peVirtualMapDdGlobal)
|
|
{
|
|
EDD_DEVLOCK eDevlock(peVirtualMapDdGlobal);
|
|
|
|
vDdUnreferenceVirtualMap(peSurface->peMap,
|
|
peVirtualMapDdGlobal,
|
|
peSurface->peDirectDrawLocal,
|
|
NtCurrentProcess(),
|
|
FALSE);
|
|
|
|
peSurface->peMap = NULL;
|
|
peSurface->peVirtualMapDdGlobal = NULL;
|
|
}
|
|
}
|
|
|
|
if (peVirtualMapDdGlobal)
|
|
{
|
|
// Decrement the the driver instance
|
|
// Note: To free the driver instance we must not be holding the devlock:
|
|
|
|
vDdDecrementReferenceCount(peVirtualMapDdGlobal);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdDeleteSurfaceObject
|
|
*
|
|
* Deletes and frees a kernel-mode representation of the surface.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdDeleteSurfaceObject(
|
|
HANDLE hSurface,
|
|
DWORD* pdwRet // For returning driver return code, may be NULL
|
|
)
|
|
{
|
|
BOOL bRet;
|
|
EDD_SURFACE* peSurface;
|
|
EDD_SURFACE* peTmp;
|
|
VOID* pvRemove;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
DWORD dwRet;
|
|
|
|
bRet = FALSE;
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
|
|
peSurface = (EDD_SURFACE*) DdHmgLock((HDD_OBJ) hSurface, DD_SURFACE_TYPE, FALSE);
|
|
|
|
if (peSurface != NULL)
|
|
{
|
|
PDEVOBJ poSurface;
|
|
PDEVOBJ poMapping;
|
|
BOOL bUnrefMappingPdev = FALSE;
|
|
|
|
peDirectDrawLocal = peSurface->peDirectDrawLocal;
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
{
|
|
EDD_SHAREDEVLOCK eDevLock(peDirectDrawGlobal);
|
|
|
|
// Prevent from deleting GDI's PDEV if this is last Virtual map refer it.
|
|
// We still need GDI's PDEV in order to call driver just below. so we
|
|
// -UN-reference it after we finish with driver.
|
|
|
|
poSurface.vInit(peDirectDrawGlobal->hdev);
|
|
poSurface.vReferencePdev();
|
|
|
|
// If we have "aliased" video memory mapping, take ref count on the owner
|
|
// of its mapping if it's different from current surface owner (due to video
|
|
// mode change)
|
|
|
|
if (peSurface->peMap)
|
|
{
|
|
// PDEVOBJ for owner of mapping
|
|
|
|
poMapping.vInit(peSurface->peVirtualMapDdGlobal->hdev);
|
|
|
|
// Is it different from current surface owner ?
|
|
|
|
if (poMapping.bValid() &&
|
|
(poMapping.hdev() != poSurface.hdev()))
|
|
{
|
|
poMapping.vReferencePdev();
|
|
bUnrefMappingPdev = TRUE;
|
|
}
|
|
}
|
|
|
|
// Note that 'bDdReleaseDC' and 'bDeleteSurface' may fail if
|
|
// another thread of the application is in the kernel using that
|
|
// DC. This can occur only if we're not currently doing the
|
|
// process cleanup code (because process cleanup ensures that
|
|
// only one thread from the process is still running). It's okay,
|
|
// because process-termination cleanup for the DC object itself
|
|
// will take care of cleanup.
|
|
|
|
if (peSurface->hdc)
|
|
{
|
|
// Note that any locks on behalf of the GetDC are taken care
|
|
// of in 'vDdDisableSurfaceObject'.
|
|
|
|
if (!bDdReleaseDC(peSurface, TRUE))
|
|
{
|
|
WARNING("bDdDeleteSurfaceObject: Couldn't release DC\n");
|
|
}
|
|
}
|
|
|
|
if (peSurface->hbmGdi)
|
|
{
|
|
// Delete the actual bitmap surface. We are doing this from
|
|
// the owning processes thread.
|
|
|
|
DxEngDeleteSurface((HSURF) peSurface->hbmGdi);
|
|
peSurface->hbmGdi = NULL;
|
|
|
|
if (peSurface->hpalGdi)
|
|
{
|
|
EngDeletePalette(peSurface->hpalGdi);
|
|
peSurface->hpalGdi = NULL;
|
|
}
|
|
}
|
|
|
|
DDKSURF(("DDKSURF: Removing %X (%X)\n", hSurface, peSurface));
|
|
|
|
pvRemove = DdHmgRemoveObject((HDD_OBJ) hSurface,
|
|
DdHmgQueryLock((HDD_OBJ) hSurface),
|
|
0,
|
|
TRUE,
|
|
DD_SURFACE_TYPE);
|
|
|
|
ASSERTGDI(pvRemove != NULL, "Outstanding surfaces locks");
|
|
|
|
// Remove any attachments:
|
|
|
|
vDdDeleteReferringAttachments(peSurface);
|
|
|
|
// Uncompleted surfaces are marked as 'lost' until they're completed,
|
|
// but we still have to call the driver if that's the case:
|
|
|
|
if (!(peSurface->bLost) ||
|
|
!(peSurface->fl & DD_SURFACE_FLAG_CREATE_COMPLETE))
|
|
{
|
|
vDdDisableSurfaceObject(peDirectDrawGlobal, peSurface, &dwRet);
|
|
}
|
|
|
|
if (peSurface->peMap)
|
|
{
|
|
vDdReleaseVirtualMap(peSurface);
|
|
}
|
|
|
|
// Remove from the surface linked-list:
|
|
|
|
RemoveEntryList(&(peSurface->List_eSurface));
|
|
|
|
// Decrement number of surface in DirectDrawLocal.
|
|
|
|
peDirectDrawLocal->cSurface--;
|
|
|
|
// The surface object is about to be freed, call CreateSurfaceEx, to
|
|
// inform the driver to disassociate the cookie if the driver can
|
|
|
|
if ((peDirectDrawGlobal->Miscellaneous2CallBacks.CreateSurfaceEx)
|
|
&& (peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
&& (peSurface->pGraphicsDeviceCreator == poSurface.pGraphicsDevice())
|
|
&& (0 != peSurface->dwSurfaceHandle)
|
|
)
|
|
{
|
|
DD_CREATESURFACEEXDATA CreateSurfaceExData;
|
|
ASSERTGDI(NULL==peSurface->hSecure,
|
|
"bDdDeleteSurfaceObject: SYSMEM object not unsecured upon delete");
|
|
peSurface->fpVidMem = NULL;
|
|
CreateSurfaceExData.ddRVal = DDERR_GENERIC;
|
|
CreateSurfaceExData.dwFlags = 0;
|
|
CreateSurfaceExData.lpDDLcl = peDirectDrawLocal;
|
|
CreateSurfaceExData.lpDDSLcl = peSurface;
|
|
// just notify driver that this system memory surface has been freed
|
|
peDirectDrawGlobal->Miscellaneous2CallBacks.CreateSurfaceEx(&CreateSurfaceExData);
|
|
|
|
}
|
|
|
|
// If the surface has some outstanding system memory that needs
|
|
// to be freed, now's the time to do it.
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_DEFER_USERMEM)
|
|
{
|
|
DD_USERMEM_DEFER* pDefer = peDirectDrawGlobal->pUserMemDefer;
|
|
DD_USERMEM_DEFER* pLast = NULL;
|
|
DD_USERMEM_DEFER* pDeferTemp;
|
|
|
|
while (pDefer != NULL)
|
|
{
|
|
pDeferTemp = pDefer;
|
|
pDefer = pDefer->pNext;
|
|
if (pDeferTemp->peSurface == peSurface)
|
|
{
|
|
SafeFreeUserMem(pDeferTemp->pUserMem, peDirectDrawLocal->Process);
|
|
|
|
if (pLast == NULL)
|
|
{
|
|
peDirectDrawGlobal->pUserMemDefer = pDefer;
|
|
}
|
|
else
|
|
{
|
|
pLast->pNext = pDefer;
|
|
}
|
|
VFREEMEM(pDeferTemp);
|
|
}
|
|
else
|
|
{
|
|
pLast = pDeferTemp;
|
|
}
|
|
}
|
|
}
|
|
|
|
// We're all done with this object, so free the memory and
|
|
// leave:
|
|
|
|
DdFreeObject(peSurface, DD_SURFACE_TYPE);
|
|
}
|
|
|
|
// Now, we've done. release GDI's PDEV if this is last one.
|
|
|
|
if (bUnrefMappingPdev)
|
|
{
|
|
poMapping.vUnreferencePdev();
|
|
}
|
|
|
|
poSurface.vUnreferencePdev();
|
|
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING1("bDdDeleteSurfaceObject: Bad handle or object was busy\n");
|
|
}
|
|
|
|
if (pdwRet != NULL)
|
|
{
|
|
*pdwRet = dwRet;
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdDisableAllDirectDrawObjects
|
|
*
|
|
* Temporarily disables all DirectDraw surfaces and local objects.
|
|
*
|
|
* NOTE: Caller must be holding User critical section.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdDisableAllDirectDrawObjects(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
|
|
)
|
|
{
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_DXDIRECTDRAW* peDxDirectDraw;
|
|
EDD_SURFACE* peSurface;
|
|
NTSTATUS status;
|
|
|
|
DD_ASSERTSHAREDEVLOCK();
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
// We may have to wait the standard 7 seconds for any locks to be
|
|
// released before we go ahead and let the mode change happen. We
|
|
// do this only when cDirectDrawDisableLocks() == 1 to allow the
|
|
// HDEV to be disabled recursively (i.e., this routine is re-entrant).
|
|
|
|
peDirectDrawGlobal->bSuspended = TRUE;
|
|
|
|
if (peDirectDrawGlobal->cSurfaceLocks >
|
|
peDirectDrawGlobal->cSurfaceAliasedLocks)
|
|
{
|
|
// Release the devlock while waiting on the event:
|
|
|
|
DxEngUnlockHdev(po.hdev());
|
|
|
|
status = KeWaitForSingleObject(peDirectDrawGlobal->pAssertModeEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
(LARGE_INTEGER*) &peDirectDrawGlobal->
|
|
llAssertModeTimeout);
|
|
|
|
ASSERTGDI(NT_SUCCESS(status), "Wait error\n");
|
|
|
|
DxEngLockHdev(po.hdev());
|
|
|
|
// Now that we have the devlock, reset the event to not-signaled
|
|
// for the next time we have to wait on someone's DirectDraw Lock
|
|
// (someone may have signaled the event after the time-out, but
|
|
// before we managed to acquire the devlock):
|
|
|
|
KeResetEvent(peDirectDrawGlobal->pAssertModeEvent);
|
|
}
|
|
|
|
// Mark all surfaces associated with this device as lost and unmap all
|
|
// views of the frame buffer:
|
|
|
|
for (peDirectDrawLocal = peDirectDrawGlobal->peDirectDrawLocalList;
|
|
peDirectDrawLocal != NULL;
|
|
peDirectDrawLocal = peDirectDrawLocal->peDirectDrawLocalNext)
|
|
{
|
|
peSurface = peDirectDrawLocal->peSurface_Enum(NULL);
|
|
|
|
while (peSurface)
|
|
{
|
|
if (!(peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
|
|
{
|
|
// Lost video memory surface.
|
|
|
|
if((peSurface->dwFlags & DDRAWISURF_DRIVERMANAGED) &&
|
|
!(peSurface->ddsCapsEx.dwCaps2 & DDSCAPS2_DONOTPERSIST))
|
|
{
|
|
vDdLooseManagedSurfaceObject(peDirectDrawGlobal,
|
|
peSurface,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
vDdDisableSurfaceObject(peDirectDrawGlobal,
|
|
peSurface,
|
|
NULL);
|
|
}
|
|
}
|
|
else if ((peDirectDrawGlobal->Miscellaneous2CallBacks.CreateSurfaceEx)
|
|
&& (peSurface->pGraphicsDeviceCreator == po.pGraphicsDevice())
|
|
&& (0 != peSurface->dwSurfaceHandle))
|
|
{
|
|
// Disassociate this system memory surface from driver.
|
|
|
|
DD_CREATESURFACEEXDATA CreateSurfaceExData;
|
|
FLATPTR fpVidMem = peSurface->fpVidMem; // keep backup
|
|
PDD_ATTACHLIST lpAttachList = peSurface->lpAttachList; // keep backup
|
|
PDD_ATTACHLIST lpAttachListFrom = peSurface->lpAttachListFrom; // keep backup
|
|
peSurface->fpVidMem = NULL;
|
|
peSurface->lpAttachList = NULL;
|
|
peSurface->lpAttachListFrom = NULL;
|
|
CreateSurfaceExData.ddRVal = DDERR_GENERIC;
|
|
CreateSurfaceExData.dwFlags = 0;
|
|
CreateSurfaceExData.lpDDLcl = peDirectDrawLocal;
|
|
CreateSurfaceExData.lpDDSLcl = peSurface;
|
|
peDirectDrawGlobal->Miscellaneous2CallBacks.CreateSurfaceEx(&CreateSurfaceExData);
|
|
peSurface->fpVidMem = fpVidMem; // restore backup
|
|
peSurface->lpAttachList = lpAttachList; // restore backup
|
|
peSurface->lpAttachListFrom = lpAttachListFrom; // restore backup
|
|
|
|
// workaround for smidisp.dll and just in case driver didn't clear-out dwReserved1
|
|
|
|
if (((DD_SURFACE_GLOBAL *)peSurface)->dwReserved1)
|
|
{
|
|
WARNING("Driver forget to clear SURFACE_GBL.dwReserved1 at CreateSurfaceEx()");
|
|
}
|
|
if (((DD_SURFACE_LOCAL *)peSurface)->dwReserved1)
|
|
{
|
|
WARNING("Driver forget to clear SURFACE_LCL.dwReserved1 at CreateSurfaceEx()");
|
|
}
|
|
|
|
((DD_SURFACE_GLOBAL *)peSurface)->dwReserved1 = 0;
|
|
((DD_SURFACE_LOCAL *)peSurface)->dwReserved1 = 0;
|
|
}
|
|
|
|
peSurface = peDirectDrawLocal->peSurface_Enum(peSurface);
|
|
}
|
|
|
|
vDdDisableDirectDrawObject(peDirectDrawLocal);
|
|
}
|
|
|
|
ASSERTGDI(peDirectDrawGlobal->cSurfaceLocks == 0,
|
|
"There was a mismatch between global count of locks and actual");
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DxDdGetDirectDrawBounds
|
|
*
|
|
* Gets the accumulated blt access rectangle to the primary surface. Returns
|
|
* FALSE if a DirectDraw blt to the primary has not occurred.
|
|
*
|
|
* 4-Nov-1998 -by- John Stephens [johnstep]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
DxDdGetDirectDrawBounds(
|
|
HDEV hdev,
|
|
RECT* prcBounds
|
|
)
|
|
{
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
peDirectDrawGlobal = po.peDirectDrawGlobal();
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
if (peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_BOUNDS_SET)
|
|
{
|
|
// Return the bounds rectangle and reset the bounds flag:
|
|
|
|
*((RECTL*) prcBounds) = peDirectDrawGlobal->rclBounds;
|
|
peDirectDrawGlobal->fl &= ~DD_GLOBAL_FLAG_BOUNDS_SET;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdRestoreSystemMemorySurface
|
|
*
|
|
* Reassociate dwSurfaceHandle to kernel surface by calling driver's CreateSurfaceEx
|
|
*
|
|
* 2-May-2002 -by- Hideyuki Nagase [hideyukn]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdRestoreSystemMemorySurface(
|
|
HDEV hdev
|
|
)
|
|
{
|
|
PDEVOBJ po(hdev);
|
|
EDD_DIRECTDRAW_GLOBAL *peDirectDrawGlobal = po.peDirectDrawGlobal();
|
|
|
|
// Reassociate system memory surface to driver (which disassociated by ResumeDirectDraw)
|
|
|
|
if (peDirectDrawGlobal->Miscellaneous2CallBacks.CreateSurfaceEx)
|
|
{
|
|
for (EDD_DIRECTDRAW_LOCAL *peDirectDrawLocal = peDirectDrawGlobal->peDirectDrawLocalList;
|
|
peDirectDrawLocal != NULL;
|
|
peDirectDrawLocal = peDirectDrawLocal->peDirectDrawLocalNext)
|
|
{
|
|
EDD_SURFACE *peSurface = peDirectDrawLocal->peSurface_Enum(NULL);
|
|
|
|
while (peSurface)
|
|
{
|
|
if ((peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
&& (peSurface->pGraphicsDeviceCreator == po.pGraphicsDevice())
|
|
&& (0 != peSurface->dwSurfaceHandle)
|
|
&& (peSurface->ddpfSurface.dwFlags & DDPF_FOURCC))
|
|
{
|
|
switch (peSurface->ddpfSurface.dwFourCC)
|
|
{
|
|
case FOURCC_DXT1:
|
|
case FOURCC_DXT2:
|
|
case FOURCC_DXT3:
|
|
case FOURCC_DXT4:
|
|
case FOURCC_DXT5:
|
|
peSurface->wWidth = peSurface->wWidthOriginal;
|
|
peSurface->wHeight = peSurface->wHeightOriginal;
|
|
}
|
|
}
|
|
|
|
peSurface = peDirectDrawLocal->peSurface_Enum(peSurface);
|
|
}
|
|
|
|
KeAttachProcess(PsGetProcessPcb(peDirectDrawLocal->Process));
|
|
|
|
peSurface = peDirectDrawLocal->peSurface_Enum(NULL);
|
|
|
|
while (peSurface)
|
|
{
|
|
// Only restore when this system memory surface previously
|
|
// called to this driver and we called CreateSurfaceEx.
|
|
|
|
if ((peSurface->fl & DD_SURFACE_FLAG_SYSMEM_CREATESURFACEEX)
|
|
&& (peSurface->pGraphicsDeviceCreator == po.pGraphicsDevice()))
|
|
{
|
|
DD_CREATESURFACEEXDATA CreateSurfaceExData;
|
|
|
|
ASSERTGDI(peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY,
|
|
"DXG:ResumeDirectDraw: no system memory flag");
|
|
ASSERTGDI(peSurface->dwSurfaceHandle != 0,
|
|
"DXG:ResumeDirectDraw: dwSurfaceHandle is 0");
|
|
|
|
CreateSurfaceExData.dwFlags = 0;
|
|
CreateSurfaceExData.ddRVal = DDERR_GENERIC;
|
|
CreateSurfaceExData.lpDDLcl = peDirectDrawLocal;
|
|
CreateSurfaceExData.lpDDSLcl = peSurface;
|
|
po.peDirectDrawGlobal()->Miscellaneous2CallBacks.CreateSurfaceEx(&CreateSurfaceExData);
|
|
|
|
if (CreateSurfaceExData.ddRVal != DD_OK)
|
|
{
|
|
WARNING("DxDdResumeDirectDraw(): Reassociate system memory surface failed");
|
|
}
|
|
}
|
|
|
|
peSurface = peDirectDrawLocal->peSurface_Enum(peSurface);
|
|
}
|
|
|
|
KeDetachProcess();
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DxDdSuspendDirectDraw
|
|
*
|
|
* Temporarily disables DirectDraw for the specified device.
|
|
*
|
|
* NOTE: Caller must be holding User critical section.
|
|
*
|
|
* NOTE: Caller must NOT be holding devlock, unless DirectDraw is already
|
|
* disabled.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
DxDdSuspendDirectDraw(
|
|
HDEV hdev,
|
|
ULONG fl
|
|
)
|
|
{
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
LONG* pl;
|
|
HDEV hdevCurrent;
|
|
BOOL bChildren = (fl & DXG_SR_DDRAW_CHILDREN);
|
|
|
|
// Bump the mode uniqueness to let user-mode DirectDraw know that
|
|
// someone else has done a mode change. (Full-screen switches count as
|
|
// full-screen, too). Do it interlocked because we're not holding a
|
|
// global lock:
|
|
|
|
INC_DISPLAY_UNIQUENESS();
|
|
|
|
// If bChildren is TRUE, make sure we've really got a meta driver:
|
|
|
|
if (bChildren)
|
|
{
|
|
PDEVOBJ po(hdev);
|
|
ASSERTGDI(po.bValid() && po.bDisplayPDEV(), "Invalid HDEV");
|
|
|
|
bChildren = po.bMetaDriver();
|
|
}
|
|
|
|
hdevCurrent = bChildren ? DxEngEnumerateHdev(NULL) : hdev;
|
|
|
|
do
|
|
{
|
|
PDEVOBJ po(hdevCurrent);
|
|
ASSERTGDI(po.bValid(), "Invalid HDEV");
|
|
ASSERTGDI(po.bDisplayPDEV(), "Not a display HDEV");
|
|
|
|
if (!bChildren || (po.hdevParent() == hdev))
|
|
{
|
|
peDirectDrawGlobal = po.peDirectDrawGlobal();
|
|
|
|
EDD_SHARELOCK eShareLock(FALSE);
|
|
|
|
if (fl & DXG_SR_DDRAW_MODECHANGE)
|
|
{
|
|
// ShareLock must be held by caller for video mode change.
|
|
|
|
DD_ASSERTSHAREDEVLOCK();
|
|
|
|
// We need to completely release the devlock soon, so we must not
|
|
// be called with the devlock already held. If we don't do this,
|
|
// any thread calling Unlock will be locked out until the timeout.
|
|
|
|
DD_ASSERTNODEVLOCK(peDirectDrawGlobal);
|
|
}
|
|
else
|
|
{
|
|
eShareLock.vLock();
|
|
}
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
ASSERTGDI(peDirectDrawGlobal->hdev != NULL,
|
|
"Can't suspend DirectDraw on an HDEV that was never DDraw enabled!");
|
|
|
|
if (po.cDirectDrawDisableLocks() == 0)
|
|
{
|
|
// Notify any kernel-mode DXAPI clients that have hooked the
|
|
// relevant event:
|
|
|
|
vDdNotifyEvent(peDirectDrawGlobal, DDEVENT_PREDOSBOX);
|
|
|
|
// Disable all DirectDraw object.
|
|
|
|
vDdDisableAllDirectDrawObjects(peDirectDrawGlobal);
|
|
}
|
|
|
|
// Increment the disable lock-count event if a DirectDraw global
|
|
// object hasn't been created:
|
|
|
|
po.cDirectDrawDisableLocks(po.cDirectDrawDisableLocks() + 1);
|
|
}
|
|
|
|
if (bChildren)
|
|
{
|
|
hdevCurrent = DxEngEnumerateHdev(hdevCurrent);
|
|
}
|
|
|
|
} while (bChildren && hdevCurrent);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DxDdResumeDirectDraw
|
|
*
|
|
* Permits DirectDraw to be reenabled for the specified device.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
DxDdResumeDirectDraw(
|
|
HDEV hdev,
|
|
ULONG fl
|
|
)
|
|
{
|
|
LONG* pl;
|
|
HDEV hdevCurrent;
|
|
BOOL bChildren = fl & DXG_SR_DDRAW_CHILDREN;
|
|
|
|
// Bump the mode uniqueness again. We do this both before and after
|
|
// the mode change actually occurs to give DirectDraw proper
|
|
// notification. If kernel-mode starts failing DdBlt calls because
|
|
// the mode has changed, this implies that we have to let DirectDraw
|
|
// know before the mode change occurs; but if we let DirectDraw know
|
|
// only before the mode change occurs, it might re-enable us before
|
|
// the new mode is actually set, so we also have to let it know after
|
|
// the mode change has occured.
|
|
|
|
INC_DISPLAY_UNIQUENESS();
|
|
|
|
// If bChildren is TRUE, make sure we've really got a meta driver:
|
|
|
|
if (bChildren)
|
|
{
|
|
PDEVOBJ po(hdev);
|
|
ASSERTGDI(po.bValid() && po.bDisplayPDEV(), "Invalid HDEV");
|
|
|
|
bChildren = po.bMetaDriver();
|
|
}
|
|
|
|
hdevCurrent = bChildren ? DxEngEnumerateHdev(NULL) : hdev;
|
|
|
|
do
|
|
{
|
|
PDEVOBJ po(hdevCurrent);
|
|
ASSERTGDI(po.bValid(), "Invalid HDEV");
|
|
ASSERTGDI(po.bDisplayPDEV(), "Not a display HDEV");
|
|
|
|
if (!bChildren || (po.hdevParent() == hdev))
|
|
{
|
|
// Decrement the disable lock-count even if a DirectDraw global object
|
|
// hasn't been created:
|
|
|
|
EDD_DEVLOCK eDevlock(po.hdev());
|
|
|
|
ASSERTGDI(po.cDirectDrawDisableLocks() != 0,
|
|
"Must have called disable previously to be able to enable DirectDraw.");
|
|
|
|
po.cDirectDrawDisableLocks(po.cDirectDrawDisableLocks() - 1);
|
|
|
|
if (po.cDirectDrawDisableLocks() == 0)
|
|
{
|
|
// Notify any kernel-mode DXAPI clients that have hooked the relevant
|
|
// event. Note that thie mode change is done, but DirectDraw is still
|
|
// in a suspended state. [Is that a problem?]
|
|
|
|
vDdNotifyEvent(po.peDirectDrawGlobal(), DDEVENT_POSTDOSBOX);
|
|
|
|
// Reassociate system memory surface if needed.
|
|
|
|
vDdRestoreSystemMemorySurface(po.hdev());
|
|
}
|
|
}
|
|
|
|
if (bChildren)
|
|
{
|
|
hdevCurrent = DxEngEnumerateHdev(hdevCurrent);
|
|
}
|
|
|
|
} while (bChildren && hdevCurrent);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DxDdDynamicModeChange
|
|
*
|
|
* Transfers DirectDraw driver instances between two PDEVs.
|
|
*
|
|
* The devlock and handle manager semaphore must be held to call this function!
|
|
*
|
|
* NOTE: This is the last step that should be taken in the dynamic mode
|
|
* change process, so that in this routine we can assume that the
|
|
* call tables and the like for the respective HDEVs have already
|
|
* been swapped.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
DxDdDynamicModeChange(
|
|
HDEV hdevOld,
|
|
HDEV hdevNew,
|
|
ULONG fl
|
|
)
|
|
{
|
|
DD_DIRECTDRAW_GLOBAL_DRIVER_DATA GlobalDriverDataSwap;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobalOld;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobalNew;
|
|
D3DNTHAL_OBJECT* pdhobj;
|
|
EDD_SURFACE* peSurface;
|
|
HDD_OBJ hobj;
|
|
LONG cReferencesOld;
|
|
LONG cReferencesNew;
|
|
LONG cAdjustOld;
|
|
LONG cAdjustNew;
|
|
FLONG flOld;
|
|
FLONG flNew;
|
|
LPDDVIDEOPORTCAPS lpDDVideoPortCaps;
|
|
DWORD dwHeap;
|
|
VIDEOMEMORY* pHeap;
|
|
DWORD dwHeapNew;
|
|
VIDEOMEMORY* pHeapNew;
|
|
BOOL bSwappedAGP;
|
|
|
|
PDEVOBJ poOld(hdevOld);
|
|
PDEVOBJ poNew(hdevNew);
|
|
|
|
peDirectDrawGlobalOld = poOld.peDirectDrawGlobal();
|
|
peDirectDrawGlobalNew = poNew.peDirectDrawGlobal();
|
|
|
|
DDKHEAP(("peDDGOld=%lx, cDriverReferences=%d\n",
|
|
peDirectDrawGlobalOld, peDirectDrawGlobalOld->cDriverReferences));
|
|
DDKHEAP(("peDDGNew=%lx, cDriverReferences=%d\n",
|
|
peDirectDrawGlobalNew, peDirectDrawGlobalNew->cDriverReferences));
|
|
|
|
// Notify any kernel-mode DXAPI clients that have hooked the relevant
|
|
// events.
|
|
|
|
vDdNotifyEvent(peDirectDrawGlobalOld, DDEVENT_PRERESCHANGE);
|
|
vDdNotifyEvent(peDirectDrawGlobalOld, DDEVENT_POSTRESCHANGE);
|
|
vDdNotifyEvent(peDirectDrawGlobalNew, DDEVENT_PRERESCHANGE);
|
|
vDdNotifyEvent(peDirectDrawGlobalNew, DDEVENT_POSTRESCHANGE);
|
|
|
|
// The DD_GLOBAL_FLAG_DRIVER_ENABLED flag transfers to the new PDEV
|
|
// along with the driver instance:
|
|
|
|
flOld = peDirectDrawGlobalOld->fl;
|
|
flNew = peDirectDrawGlobalNew->fl;
|
|
|
|
peDirectDrawGlobalOld->fl = (flOld & ~DD_GLOBAL_FLAG_DRIVER_ENABLED)
|
|
| (flNew & DD_GLOBAL_FLAG_DRIVER_ENABLED)
|
|
| (DD_GLOBAL_FLAG_MODE_CHANGED);
|
|
peDirectDrawGlobalOld->bSuspended = TRUE;
|
|
peDirectDrawGlobalOld->dhpdev = poOld.dhpdev();
|
|
peDirectDrawGlobalOld->hdev = poOld.hdev();
|
|
|
|
peDirectDrawGlobalNew->fl = (flNew & ~DD_GLOBAL_FLAG_DRIVER_ENABLED)
|
|
| (flOld & DD_GLOBAL_FLAG_DRIVER_ENABLED)
|
|
| (DD_GLOBAL_FLAG_MODE_CHANGED);
|
|
peDirectDrawGlobalNew->bSuspended = TRUE;
|
|
peDirectDrawGlobalNew->dhpdev = poNew.dhpdev();
|
|
peDirectDrawGlobalNew->hdev = poNew.hdev();
|
|
|
|
// Transfer heap AGP 'handles':
|
|
//
|
|
// since AGP handle stay with its driver instance.
|
|
|
|
pHeap = peDirectDrawGlobalOld->pvmList;
|
|
for (dwHeap = 0;
|
|
dwHeap < peDirectDrawGlobalOld->dwNumHeaps;
|
|
pHeap++, dwHeap++)
|
|
{
|
|
if (!(pHeap->dwFlags & VIDMEM_ISHEAP) &&
|
|
!(pHeap->dwFlags & VIDMEM_HEAPDISABLED) &&
|
|
(pHeap->dwFlags & VIDMEM_ISNONLOCAL) &&
|
|
(pHeap->lpHeap != NULL) &&
|
|
(pHeap->lpHeap->hdevAGP == AGP_HDEV(peDirectDrawGlobalOld)))
|
|
{
|
|
pHeap->lpHeap->hdevAGP = AGP_HDEV(peDirectDrawGlobalNew);
|
|
}
|
|
}
|
|
|
|
pHeap = peDirectDrawGlobalNew->pvmList;
|
|
for (dwHeap = 0;
|
|
dwHeap < peDirectDrawGlobalNew->dwNumHeaps;
|
|
pHeap++, dwHeap++)
|
|
{
|
|
if (!(pHeap->dwFlags & VIDMEM_ISHEAP) &&
|
|
!(pHeap->dwFlags & VIDMEM_HEAPDISABLED) &&
|
|
(pHeap->dwFlags & VIDMEM_ISNONLOCAL) &&
|
|
(pHeap->lpHeap != NULL) &&
|
|
(pHeap->lpHeap->hdevAGP == AGP_HDEV(peDirectDrawGlobalNew)))
|
|
{
|
|
pHeap->lpHeap->hdevAGP = AGP_HDEV(peDirectDrawGlobalOld);
|
|
}
|
|
}
|
|
|
|
// DirectDraw objects and surfaces stay with the PDEV, but driver
|
|
// instances are swapped:
|
|
|
|
RtlCopyMemory(&GlobalDriverDataSwap,
|
|
(DD_DIRECTDRAW_GLOBAL_DRIVER_DATA*) peDirectDrawGlobalOld,
|
|
sizeof(DD_DIRECTDRAW_GLOBAL_DRIVER_DATA));
|
|
|
|
RtlCopyMemory((DD_DIRECTDRAW_GLOBAL_DRIVER_DATA*) peDirectDrawGlobalOld,
|
|
(DD_DIRECTDRAW_GLOBAL_DRIVER_DATA*) peDirectDrawGlobalNew,
|
|
sizeof(DD_DIRECTDRAW_GLOBAL_DRIVER_DATA));
|
|
|
|
RtlCopyMemory((DD_DIRECTDRAW_GLOBAL_DRIVER_DATA*) peDirectDrawGlobalNew,
|
|
&GlobalDriverDataSwap,
|
|
sizeof(DD_DIRECTDRAW_GLOBAL_DRIVER_DATA));
|
|
|
|
// If the old object had an initialized AGP heap, make sure that it stays
|
|
// with the old object (swap it back). We only want to do this if it's
|
|
// not a one-to-many or many-to-one mode change, however.
|
|
|
|
bSwappedAGP = FALSE;
|
|
if (!poNew.bMetaDriver() &&
|
|
!poOld.bMetaDriver() &&
|
|
(poNew.pldev() == poOld.pldev()))
|
|
{
|
|
pHeap = peDirectDrawGlobalOld->pvmList;
|
|
for (dwHeap = 0;
|
|
dwHeap < peDirectDrawGlobalOld->dwNumHeaps;
|
|
pHeap++, dwHeap++)
|
|
{
|
|
if (!(pHeap->dwFlags & VIDMEM_ISHEAP) &&
|
|
!(pHeap->dwFlags & VIDMEM_HEAPDISABLED) &&
|
|
(pHeap->dwFlags & VIDMEM_ISNONLOCAL) &&
|
|
(pHeap->lpHeap != NULL) &&
|
|
(pHeap->lpHeap->pvPhysRsrv == NULL))
|
|
{
|
|
// The old object has a heap, find the corresponding heap in the
|
|
// new object.
|
|
|
|
pHeapNew = peDirectDrawGlobalNew->pvmList;
|
|
for (dwHeapNew = 0;
|
|
dwHeapNew < peDirectDrawGlobalNew->dwNumHeaps;
|
|
pHeapNew++, dwHeapNew++)
|
|
{
|
|
if ((pHeapNew->dwFlags == pHeap->dwFlags) &&
|
|
(pHeapNew->lpHeap != NULL) &&
|
|
(pHeapNew->lpHeap->pvPhysRsrv != NULL))
|
|
{
|
|
SwapHeaps( pHeap, pHeapNew );
|
|
|
|
// We used to tear down the heap and create a new one
|
|
// with each mode change, but now we keep the one heap
|
|
// active acrross mode changes. This means that we don't
|
|
// need to notify the driver the driver of the heap change,
|
|
// but this is a behavior change and some drivers depend
|
|
// on this notification so we'll do it anyway.
|
|
|
|
UpdateNonLocalHeap( peDirectDrawGlobalOld, dwHeap );
|
|
bSwappedAGP = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Also swap video port caps, which are part of the DIRETCDRAW_GLOBAL
|
|
|
|
lpDDVideoPortCaps = peDirectDrawGlobalOld->lpDDVideoPortCaps;
|
|
peDirectDrawGlobalOld->lpDDVideoPortCaps = peDirectDrawGlobalNew->lpDDVideoPortCaps;
|
|
peDirectDrawGlobalNew->lpDDVideoPortCaps = lpDDVideoPortCaps;
|
|
|
|
cReferencesNew = 0;
|
|
cReferencesOld = 0;
|
|
cAdjustNew = 0;
|
|
cAdjustOld = 0;
|
|
|
|
// Transfer ownership of any Direct3D objects to its new PDEV:
|
|
//
|
|
// since it stay with its driver instance.
|
|
|
|
DdHmgAcquireHmgrSemaphore();
|
|
|
|
hobj = 0;
|
|
while (pdhobj = (D3DNTHAL_OBJECT*) DdHmgNextObjt(hobj, D3D_HANDLE_TYPE))
|
|
{
|
|
hobj = (HDD_OBJ) pdhobj->hGet();
|
|
|
|
if (pdhobj->peDdGlobal == peDirectDrawGlobalOld)
|
|
{
|
|
pdhobj->peDdGlobal = peDirectDrawGlobalNew;
|
|
cReferencesNew++;
|
|
}
|
|
else if (pdhobj->peDdGlobal == peDirectDrawGlobalNew)
|
|
{
|
|
pdhobj->peDdGlobal = peDirectDrawGlobalOld;
|
|
cReferencesOld++;
|
|
}
|
|
}
|
|
|
|
hobj = 0;
|
|
while (peSurface = (EDD_SURFACE*) DdHmgNextObjt(hobj, DD_SURFACE_TYPE))
|
|
{
|
|
hobj = (HDD_OBJ) peSurface->hGet();
|
|
|
|
// Transfer VMEMMAPPING structures
|
|
//
|
|
// since it stay with its driver instance. We do not switch these
|
|
// for AGP surfaces since we no longer switch the AGP heaps.
|
|
|
|
if (peSurface->peVirtualMapDdGlobal == peDirectDrawGlobalOld)
|
|
{
|
|
DDKHEAP(("vDdDynamicModeChange: %x->%x matches old global\n",
|
|
peSurface, peSurface->peVirtualMapDdGlobal));
|
|
|
|
if ((peSurface->peMap != NULL) &&
|
|
(peSurface->peMap->fl & DD_VMEMMAPPING_FLAG_AGP) &&
|
|
bSwappedAGP)
|
|
{
|
|
cAdjustOld++;
|
|
}
|
|
else
|
|
{
|
|
peSurface->peVirtualMapDdGlobal = peDirectDrawGlobalNew;
|
|
cReferencesNew++;
|
|
}
|
|
}
|
|
else if (peSurface->peVirtualMapDdGlobal == peDirectDrawGlobalNew)
|
|
{
|
|
DDKHEAP(("vDdDynamicModeChange: %x->%x matches new global\n",
|
|
peSurface, peSurface->peVirtualMapDdGlobal));
|
|
if ((peSurface->peMap != NULL) &&
|
|
(peSurface->peMap->fl & DD_VMEMMAPPING_FLAG_AGP) &&
|
|
bSwappedAGP)
|
|
{
|
|
cAdjustNew++;
|
|
}
|
|
else
|
|
{
|
|
peSurface->peVirtualMapDdGlobal = peDirectDrawGlobalOld;
|
|
cReferencesOld++;
|
|
}
|
|
}
|
|
|
|
// If surface is "driver managed"...
|
|
//
|
|
// driver managed surface will stay with its driver instance.
|
|
|
|
if (peSurface->dwFlags & DDRAWISURF_DRIVERMANAGED)
|
|
{
|
|
// And if we are doing mode change across "different" video drivers
|
|
// mark wrong driver flag while it live in there until go back
|
|
// to original creator driver.
|
|
//
|
|
// And peDdGlobalCreator should go with driver instance.
|
|
|
|
// If video mode change happen with same driver, surface with just stay where it is.
|
|
|
|
if (poOld.pldev() == poNew.pldev())
|
|
{
|
|
// Driver reference has been swapped, but this surface will continue to
|
|
// stick with same, so need adjust it (= transfer back).
|
|
|
|
if (peSurface->peDdGlobalCreator == peDirectDrawGlobalOld)
|
|
{
|
|
if (!(peSurface->bLost))
|
|
{
|
|
cAdjustOld++;
|
|
}
|
|
|
|
#if DBG_HIDEYUKN
|
|
KdPrint(("DXG: same pldev, stay with old\n"));
|
|
#endif
|
|
}
|
|
else if (peSurface->peDdGlobalCreator == peDirectDrawGlobalNew)
|
|
{
|
|
if (!(peSurface->bLost))
|
|
{
|
|
cAdjustNew++;
|
|
}
|
|
|
|
#if DBG_HIDEYUKN
|
|
KdPrint(("DXG: same pldev, stay with new\n"));
|
|
#endif
|
|
}
|
|
}
|
|
else // if (poOld.pldev() != poNew.poNew())
|
|
{
|
|
if (peSurface->peDdGlobalCreator == peDirectDrawGlobalOld)
|
|
{
|
|
// This surface is currently associated to old driver
|
|
// (= where actually will be new after swap)
|
|
|
|
// Transfer the surface to new (where it will be Old).
|
|
|
|
peSurface->peDdGlobalCreator = peDirectDrawGlobalNew;
|
|
|
|
if (peSurface->peDdGlobalCreator == peSurface->peDirectDrawGlobal)
|
|
{
|
|
peSurface->fl &= ~DD_SURFACE_FLAG_WRONG_DRIVER;
|
|
|
|
#if DBG_HIDEYUKN
|
|
KdPrint(("DXG: diff pldev, move to new, clear wrong driver\n"));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
peSurface->fl |= DD_SURFACE_FLAG_WRONG_DRIVER;
|
|
|
|
#if DBG_HIDEYUKN
|
|
KdPrint(("DXG: diff pldev, move to new, set wrong driver\n"));
|
|
#endif
|
|
}
|
|
|
|
// Driver reference count has been swapped already in above. so new DdGlobal
|
|
// already has reference for this surface. Increment this for later verification.
|
|
|
|
if (!(peSurface->bLost))
|
|
{
|
|
cReferencesNew++;
|
|
}
|
|
}
|
|
else if (peSurface->peDdGlobalCreator == peDirectDrawGlobalNew)
|
|
{
|
|
// This surface is currently associated to new (where it will be old after swap)
|
|
|
|
// Transfer the surface to old (where it will be new).
|
|
|
|
peSurface->peDdGlobalCreator = peDirectDrawGlobalOld;
|
|
|
|
if (peSurface->peDdGlobalCreator == peSurface->peDirectDrawGlobal)
|
|
{
|
|
peSurface->fl &= ~DD_SURFACE_FLAG_WRONG_DRIVER;
|
|
|
|
#if DBG_HIDEYUKN
|
|
KdPrint(("DXG: diff pldev, move to old, clear wrong driver\n"));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
peSurface->fl |= DD_SURFACE_FLAG_WRONG_DRIVER;
|
|
|
|
#if DBG_HIDEYUKN
|
|
KdPrint(("DXG: diff pldev, move to old, set wrong driver\n"));
|
|
#endif
|
|
}
|
|
|
|
// if surface is not losted, make sure reference is stay with old driver
|
|
// (this is for later assertion).
|
|
|
|
if (!(peSurface->bLost))
|
|
{
|
|
cReferencesOld++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DdHmgReleaseHmgrSemaphore();
|
|
|
|
#if DBG_HIDEYUKN
|
|
KdPrint(("DXG:Reference Counts BEFORE Adjust\n"));
|
|
KdPrint(("DXG:DdGlobalOld->cDriverReference (%d) = cReferencesOld (%d) + cAdjustNew (%d)\n",
|
|
peDirectDrawGlobalOld->cDriverReferences,cReferencesOld,cAdjustNew));
|
|
KdPrint(("DXG:DdGlobalNew->cDriverReference (%d) = cReferencesNew (%d) + cAdjustOld (%d)\n",
|
|
peDirectDrawGlobalNew->cDriverReferences,cReferencesNew,cAdjustOld));
|
|
#endif
|
|
|
|
// We used to transfer all of the surfaces from the old PDEV to the new
|
|
// one, but now we only do that for the non-agp surfaces, which means that
|
|
// we need to adjust the cDriverReferences accordingly.
|
|
|
|
ASSERTGDI(cReferencesOld + cAdjustNew == peDirectDrawGlobalOld->cDriverReferences,
|
|
"Mis-match in old D3D driver references");
|
|
ASSERTGDI(cReferencesNew + cAdjustOld == peDirectDrawGlobalNew->cDriverReferences,
|
|
"Mis-match in new D3D driver references");
|
|
|
|
// Transfer the PDEV references:
|
|
//
|
|
// I'm going to try to explain this. DXG keeps a single ref count on each
|
|
// PDEV that either has a surface or a context associated with it, so on
|
|
// entering this funtion, we have a single ref count on the old PDEV.
|
|
// If we transfer all of the surfaces to the new PDEV, then we can decrement
|
|
// from the ref from the old PDEV and add on to the new PDEV. If some of the
|
|
// surfaces continue with the old PDEV, however, then we need to make sure
|
|
// that we keep ref on that PDEV as well.
|
|
|
|
peDirectDrawGlobalNew->cDriverReferences -= cAdjustOld;
|
|
peDirectDrawGlobalNew->cDriverReferences += cAdjustNew;
|
|
peDirectDrawGlobalOld->cDriverReferences -= cAdjustNew;
|
|
peDirectDrawGlobalOld->cDriverReferences += cAdjustOld;
|
|
|
|
#if DBG_HIDEYUKN
|
|
KdPrint(("DXG:Reference Counts AFTER Adjust\n"));
|
|
KdPrint(("DXG:DdGlobalOld->cDriverReferences = %d\n",peDirectDrawGlobalOld->cDriverReferences));
|
|
KdPrint(("DXG:DdGlobalNew->cDriverReferences = %d\n",peDirectDrawGlobalNew->cDriverReferences));
|
|
#endif
|
|
|
|
if (cReferencesNew || cAdjustOld)
|
|
{
|
|
// The old PDEV had references on it
|
|
if (peDirectDrawGlobalOld->cDriverReferences == 0)
|
|
{
|
|
//but it doesn't now, so remove it
|
|
poOld.vUnreferencePdev();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The old PDEV did not have refernces on it
|
|
if (peDirectDrawGlobalOld->cDriverReferences > 0)
|
|
{
|
|
// but it does not, so add it
|
|
poOld.vReferencePdev();
|
|
}
|
|
}
|
|
|
|
if (cReferencesOld || cAdjustNew)
|
|
{
|
|
// The new PDEV had references on it
|
|
if (peDirectDrawGlobalNew->cDriverReferences == 0)
|
|
{
|
|
// but it doesn't now, so remove it
|
|
poNew.vUnreferencePdev();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The new PDEV did not have references on it
|
|
if (peDirectDrawGlobalNew->cDriverReferences > 0)
|
|
{
|
|
// but it does now, so add it
|
|
poNew.vReferencePdev();
|
|
}
|
|
}
|
|
|
|
// Move DirectDraw lock count.
|
|
//
|
|
// - this point, the disabled flag has *NOT* been swapped YET, so
|
|
// we need to move the lock count to where it *will be* disabled "after this call"
|
|
// not the device currently disabled.
|
|
//
|
|
// So if poNew is disabled at here, GDI will make poOld disabled (after this call),
|
|
// thus transfer disabled lock to poOld.
|
|
|
|
if (!poNew.bMetaDriver() && !poOld.bMetaDriver())
|
|
{
|
|
// Mode change between display drivers.
|
|
|
|
if (poNew.bDisabled())
|
|
{
|
|
// These asserts make sure that nothing happens other than cLock count adjustment
|
|
|
|
ASSERTGDI(poOld.cDirectDrawDisableLocks() >= 1,"Old PDEV cDirectDrawLocks <= 0");
|
|
ASSERTGDI(poNew.cDirectDrawDisableLocks() >= 2,"New PDEV cDirectDrawLocks <= 1");
|
|
|
|
poOld.cDirectDrawDisableLocks(poOld.cDirectDrawDisableLocks() + 1);
|
|
poNew.cDirectDrawDisableLocks(poNew.cDirectDrawDisableLocks() - 1);
|
|
}
|
|
|
|
if (poOld.bDisabled())
|
|
{
|
|
// These asserts make sure that nothing happens other than cLock count adjustment
|
|
|
|
ASSERTGDI(poNew.cDirectDrawDisableLocks() >= 1,"New PDEV cDirectDrawLocks <= 0");
|
|
ASSERTGDI(poOld.cDirectDrawDisableLocks() >= 2,"Old PDEV cDirectDrawLocks <= 1");
|
|
|
|
poNew.cDirectDrawDisableLocks(poNew.cDirectDrawDisableLocks() + 1);
|
|
poOld.cDirectDrawDisableLocks(poOld.cDirectDrawDisableLocks() - 1);
|
|
}
|
|
}
|
|
else if (poNew.bMetaDriver() && poOld.bMetaDriver())
|
|
{
|
|
// Mode change between DDMLs, nothing need to do.
|
|
// Because the hdev for Meta driver is ALWAYS created newly, never reused.
|
|
// (see gre\drvsup\hCreateHDEV()).
|
|
}
|
|
else if (poOld.bMetaDriver() || poNew.bMetaDriver())
|
|
{
|
|
// Since at this point, the meta driver flag has been swapped.
|
|
//
|
|
// - when poOld is meta, we are doing 1 -> 2 mode change.
|
|
// - when poNew is meta, we are doing 2 -> 1 mode change.
|
|
|
|
if (poNew.bDisabled())
|
|
{
|
|
// These asserts make sure that nothing happens other than cLock count adjustment
|
|
//
|
|
// ASSERTGDI(poOld.cDirectDrawDisableLocks() >= 1,"A: Old PDEV cDirectDrawLocks <= 0");
|
|
// ASSERTGDI(poNew.cDirectDrawDisableLocks() >= 2,"B: New PDEV cDirectDrawLocks <= 1");
|
|
|
|
poOld.cDirectDrawDisableLocks(poOld.cDirectDrawDisableLocks() + 1);
|
|
poNew.cDirectDrawDisableLocks(poNew.cDirectDrawDisableLocks() - 1);
|
|
}
|
|
|
|
if (poOld.bDisabled())
|
|
{
|
|
// These asserts make sure that nothing happens other than cLock count adjustment
|
|
//
|
|
// ASSERTGDI(poNew.cDirectDrawDisableLocks() >= 1,"C: New PDEV cDirectDrawLocks <= 0");
|
|
// ASSERTGDI(poOld.cDirectDrawDisableLocks() >= 2,"D: Old PDEV cDirectDrawLocks <= 1");
|
|
|
|
poNew.cDirectDrawDisableLocks(poNew.cDirectDrawDisableLocks() + 1);
|
|
poOld.cDirectDrawDisableLocks(poOld.cDirectDrawDisableLocks() - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdMapMemory
|
|
*
|
|
* Creates a user-mode mapping of the device's entire frame buffer in the
|
|
* current process.
|
|
*
|
|
* The devlock must be held to call this function.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vDdMapMemory(
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal,
|
|
HRESULT* pResult
|
|
)
|
|
{
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
DWORD dwRet;
|
|
DD_MAPMEMORYDATA MapMemoryData;
|
|
SIZE_T CommitSize;
|
|
HANDLE pSection;
|
|
HANDLE SectionHandle;
|
|
NTSTATUS Status;
|
|
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
if (!(peDirectDrawGlobal->CallBacks.dwFlags & DDHAL_CB32_MAPMEMORY))
|
|
{
|
|
peDirectDrawLocal->fl |= DD_LOCAL_FLAG_MEMORY_MAPPED;
|
|
peDirectDrawGlobal->cMaps++;
|
|
}
|
|
else
|
|
{
|
|
MapMemoryData.lpDD = peDirectDrawGlobal;
|
|
MapMemoryData.bMap = TRUE;
|
|
MapMemoryData.hProcess = NtCurrentProcess();
|
|
MapMemoryData.fpProcess = NULL;
|
|
|
|
dwRet = peDirectDrawGlobal->CallBacks.MapMemory(&MapMemoryData);
|
|
|
|
*pResult = MapMemoryData.ddRVal;
|
|
|
|
if (*pResult == DD_OK)
|
|
{
|
|
// Allocate new EDD_VMEMMAPPING object
|
|
peDirectDrawLocal->peMapCurrent = (EDD_VMEMMAPPING*)
|
|
PALLOCMEM(sizeof(EDD_VMEMMAPPING), ' ddG');
|
|
|
|
if (peDirectDrawLocal->peMapCurrent)
|
|
{
|
|
peDirectDrawLocal->peMapCurrent->fpProcess =
|
|
MapMemoryData.fpProcess;
|
|
peDirectDrawLocal->peMapCurrent->cReferences = 1;
|
|
|
|
peDirectDrawLocal->fpProcess = MapMemoryData.fpProcess;
|
|
peDirectDrawLocal->fl |= DD_LOCAL_FLAG_MEMORY_MAPPED;
|
|
peDirectDrawGlobal->cMaps++;
|
|
|
|
ASSERTGDI(peDirectDrawLocal->fpProcess != 0,
|
|
"Expected non-NULL fpProcess value from MapMemory");
|
|
ASSERTGDI((ULONG) peDirectDrawLocal->fpProcess
|
|
< MM_USER_PROBE_ADDRESS,
|
|
"Expected user-mode fpProcess value from MapMemory");
|
|
}
|
|
else
|
|
{
|
|
WARNING("vDdMapMemory: "
|
|
"Could not allocate memory for peMapCurrent\n");
|
|
|
|
// Clean up the driver mapping since we are failing vDdMapMemory call!
|
|
|
|
MapMemoryData.lpDD = peDirectDrawGlobal;
|
|
MapMemoryData.bMap = FALSE;
|
|
MapMemoryData.hProcess = NtCurrentProcess();
|
|
|
|
// Keep fpProcess as what driver returned at above call.
|
|
//
|
|
// MapMemoryData.fpProcess = MapMemoryData.fpProcess;
|
|
|
|
// Don't really care if this succeeds. It's bad news anyway
|
|
|
|
peDirectDrawGlobal->CallBacks.MapMemory(&MapMemoryData);
|
|
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("vDdMapMemory: Driver failed DdMapMemory\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID pDdLockSurfaceOrBuffer
|
|
*
|
|
* Returns a user-mode pointer to the surface or D3D buffer.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID*
|
|
pDdLockSurfaceOrBuffer(
|
|
EDD_SURFACE* peSurface,
|
|
BOOL bHasRect,
|
|
RECTL* pArea,
|
|
DWORD dwFlags, // DDLOCK_WAIT, DDLOCK_NOSYSLOCK
|
|
HRESULT* pResult // ddRVal result of call (may be NULL)
|
|
)
|
|
{
|
|
VOID* pvRet;
|
|
DD_LOCKDATA LockData;
|
|
DD_UNLOCKDATA UnlockData;
|
|
EDD_DIRECTDRAW_GLOBAL* peDdGlobalDriver;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
DWORD dwTmp;
|
|
DWORD dwRedraw;
|
|
PDD_SURFCB_LOCK pfnLock;
|
|
|
|
pvRet = NULL;
|
|
LockData.ddRVal = DDERR_GENERIC;
|
|
|
|
peDirectDrawLocal = peSurface->peDirectDrawLocal;
|
|
|
|
// Due to video mode change across different video driver, currently
|
|
// this "driver managed" surface is associated to different driver
|
|
// than the driver who actually manage it. So we must call the driver
|
|
// which actually manage the surface.
|
|
|
|
// Hold share lock and devlock for video mode change.
|
|
// peSurface->fl can be changed by mode change, so we need to access
|
|
// there under holding share lock.
|
|
|
|
EDD_SHARELOCK eSharelock(TRUE);
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_WRONG_DRIVER)
|
|
{
|
|
// If surface is owned by different driver, lock right driver.
|
|
|
|
if (peSurface->peDirectDrawGlobal != peSurface->peDdGlobalCreator)
|
|
{
|
|
peDdGlobalDriver = peSurface->peDdGlobalCreator;
|
|
}
|
|
|
|
// WARNING("pDdLockSurfaceOrBuffer: Lock on wrong driver");
|
|
}
|
|
else
|
|
{
|
|
peDdGlobalDriver = peSurface->peDirectDrawGlobal;
|
|
}
|
|
|
|
EDD_DEVLOCK eDevlock(peDdGlobalDriver);
|
|
|
|
// For system memory surface, just return here without involving driver.
|
|
|
|
if (peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
pvRet = (VOID*) peSurface->fpVidMem;
|
|
LockData.ddRVal = DD_OK;
|
|
goto Exit;
|
|
}
|
|
|
|
// In case if videomode change just happened, make sure new mode
|
|
// has DirectDraw capability.
|
|
|
|
if (!(peDdGlobalDriver->fl & DD_GLOBAL_FLAG_DRIVER_ENABLED))
|
|
{
|
|
LockData.ddRVal = DDERR_SURFACELOST;
|
|
goto Exit;
|
|
}
|
|
|
|
// We have to check both to see if the surface is disabled and if
|
|
// DirectDraw is disabled. We have to do the latter because we may
|
|
// be in a situtation where we're denying locks, but all the
|
|
// individual surfaces have not yet been marked as disabled.
|
|
|
|
if (peSurface->bLost)
|
|
{
|
|
LockData.ddRVal = DDERR_SURFACELOST;
|
|
goto Exit;
|
|
}
|
|
|
|
if ((peDdGlobalDriver->bSuspended) ||
|
|
(peSurface->fl & DD_SURFACE_FLAG_WRONG_DRIVER))
|
|
{
|
|
// Only the "driver managed surface" surface has DDSCAPS2_DONOTPERSIST
|
|
// can be locked when driver is suspended or surface lives in different driver.
|
|
|
|
if ((peSurface->dwFlags & DDRAWISURF_DRIVERMANAGED) &&
|
|
!(peSurface->ddsCapsEx.dwCaps2 & DDSCAPS2_DONOTPERSIST))
|
|
{
|
|
// WARNING("pDdLockSurfaceOrBuffer: Call driver other than current to lock driver managed surface");
|
|
}
|
|
else
|
|
{
|
|
LockData.ddRVal = DDERR_SURFACELOST;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
LockData.dwFlags = dwFlags & (
|
|
DDLOCK_SURFACEMEMORYPTR |
|
|
DDLOCK_DISCARDCONTENTS |
|
|
DDLOCK_NOOVERWRITE |
|
|
DDLOCK_READONLY |
|
|
DDLOCK_WRITEONLY |
|
|
DDLOCK_HASVOLUMETEXTUREBOXRECT |
|
|
DDLOCK_NODIRTYUPDATE);
|
|
LockData.lpDD = peDdGlobalDriver;
|
|
LockData.lpDDSurface = peSurface;
|
|
LockData.bHasRect = bHasRect;
|
|
|
|
if (bHasRect)
|
|
{
|
|
// Validate lock area.
|
|
|
|
LONG left, top, right, bottom;
|
|
LONG front, back, SurfaceDepth;
|
|
|
|
if ((peSurface->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME) &&
|
|
(LockData.dwFlags & DDLOCK_HASVOLUMETEXTUREBOXRECT))
|
|
{
|
|
left = pArea->left & 0xFFFF;
|
|
top = pArea->top;
|
|
right = pArea->right & 0xFFFF;
|
|
bottom = pArea->bottom;
|
|
front = (ULONG)(pArea->left) >> 16;
|
|
back = (ULONG)(pArea->right) >> 16;
|
|
SurfaceDepth = peSurface->dwBlockSizeY;
|
|
}
|
|
else
|
|
{
|
|
left = pArea->left;
|
|
top = pArea->top;
|
|
right = pArea->right;
|
|
bottom = pArea->bottom;
|
|
}
|
|
|
|
// Ensure that the driver and 'bSpTearDownSprites'
|
|
// don't fall over when given a bad rectangle:
|
|
|
|
if ((left >= right) ||
|
|
(top >= bottom) ||
|
|
(left < 0) ||
|
|
(top < 0) ||
|
|
(right > (LONG) peSurface->wWidth) ||
|
|
(bottom > (LONG) peSurface->wHeight))
|
|
{
|
|
if (!(left == 0 && right == 0 &&
|
|
(peSurface->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER) &&
|
|
(peSurface->dwFlags & DDRAWISURF_DRIVERMANAGED)))
|
|
{
|
|
bHasRect = FALSE;
|
|
}
|
|
}
|
|
|
|
if ((peSurface->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME) &&
|
|
(LockData.dwFlags & DDLOCK_HASVOLUMETEXTUREBOXRECT))
|
|
{
|
|
if ((front >= back) ||
|
|
(front < 0) ||
|
|
(back > SurfaceDepth))
|
|
{
|
|
bHasRect = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bHasRect)
|
|
{
|
|
// Lock entire surface. (all depth if volume).
|
|
|
|
LockData.rArea.left = 0;
|
|
LockData.rArea.top = 0;
|
|
LockData.rArea.right = peSurface->wWidth;
|
|
LockData.rArea.bottom = peSurface->wHeight;
|
|
|
|
// Mask off DDLOCK_HASVOLUMETEXTUREBOXRECT.
|
|
|
|
LockData.dwFlags &= ~DDLOCK_HASVOLUMETEXTUREBOXRECT;
|
|
}
|
|
else
|
|
{
|
|
LockData.rArea = *pArea;
|
|
}
|
|
|
|
if (peSurface->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM)
|
|
{
|
|
// AGP surfaces don't need fpProcess:
|
|
|
|
LockData.fpProcess = 0;
|
|
}
|
|
else
|
|
{
|
|
if (peSurface->fl & DD_SURFACE_FLAG_WRONG_DRIVER)
|
|
{
|
|
// If this surface currently lives in different driver,
|
|
// don't do video memory mapping to usermode address.
|
|
// Driver should be able to lock surface without this.
|
|
// Unless otherwise, driver should fail in Lock.
|
|
|
|
LockData.fpProcess = 0;
|
|
}
|
|
else
|
|
{
|
|
// Map the memory into the application's address space if that
|
|
// hasn't already been done:
|
|
|
|
if (!(peDirectDrawLocal->fl & DD_LOCAL_FLAG_MEMORY_MAPPED))
|
|
{
|
|
vDdMapMemory(peDirectDrawLocal, &LockData.ddRVal);
|
|
}
|
|
|
|
// Only proceed if we were successful in mapping the memory:
|
|
|
|
if (!(peDirectDrawLocal->fl & DD_LOCAL_FLAG_MEMORY_MAPPED))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
LockData.fpProcess = peDirectDrawLocal->fpProcess;
|
|
}
|
|
}
|
|
|
|
// If the surface is driver managed, we don't want to create any aliases
|
|
// so we reset the NOSYSLOCK flag:
|
|
|
|
if ((peSurface->dwFlags & DDRAWISURF_DRIVERMANAGED) &&
|
|
!(peSurface->ddsCapsEx.dwCaps2 & DDSCAPS2_DONOTPERSIST))
|
|
{
|
|
dwFlags &= ~DDLOCK_NOSYSLOCK;
|
|
}
|
|
|
|
// We allow only one "aliased" lock at any time. Thus if there already
|
|
// exists an aliased lock (peMap !=NULL) then we fail all other requests
|
|
// for locks. Also if there are already non aliased locks then we fail
|
|
// any requests for aliased locks.
|
|
// All this restrictions are put in due to the fact that we do not keep
|
|
// track of access rects for each surface in the kernel. If we did, we
|
|
// would just store a peMap pointer per access rect and not require these
|
|
// checks.
|
|
|
|
if ((peSurface->peMap ||
|
|
(peSurface->fl & DD_SURFACE_FLAG_FAKE_ALIAS_LOCK)) ||
|
|
(peSurface->cLocks && (dwFlags & DDLOCK_NOSYSLOCK)))
|
|
{
|
|
WARNING("pDdLockSurfaceOrBuffer: Failing lock since we cannot have more than one aliased lock");
|
|
LockData.ddRVal = DDERR_SURFACEBUSY;
|
|
goto Exit;
|
|
}
|
|
|
|
// If the VisRgn has changed since the application last queried
|
|
// it, fail the call with a unique error code so that they know
|
|
// to requery the VisRgn and try again. We do this only if we
|
|
// haven't been asked to wait (we assume 'bWait' is equivalent
|
|
// to 'bInternal').
|
|
|
|
if (!(dwFlags & DDLOCK_WAIT) &&
|
|
(peSurface->fl & DD_SURFACE_FLAG_PRIMARY) &&
|
|
(peSurface->iVisRgnUniqueness != VISRGN_UNIQUENESS()))
|
|
{
|
|
LockData.ddRVal = DDERR_VISRGNCHANGED;
|
|
goto Exit;
|
|
}
|
|
|
|
dwTmp = DDHAL_DRIVER_NOTHANDLED;
|
|
|
|
// Pick the appropriate lock function.
|
|
|
|
if (peSurface->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER)
|
|
{
|
|
pfnLock = peDdGlobalDriver->D3dBufCallbacks.LockD3DBuffer;
|
|
}
|
|
else
|
|
{
|
|
if (peDdGlobalDriver->SurfaceCallBacks.dwFlags & DDHAL_SURFCB32_LOCK)
|
|
{
|
|
pfnLock = peDdGlobalDriver->SurfaceCallBacks.Lock;
|
|
}
|
|
else
|
|
{
|
|
pfnLock = NULL;
|
|
}
|
|
}
|
|
|
|
if (pfnLock != NULL)
|
|
{
|
|
do
|
|
{
|
|
dwTmp = pfnLock(&LockData);
|
|
} while ((dwFlags & DDLOCK_WAIT) &&
|
|
(dwTmp == DDHAL_DRIVER_HANDLED) &&
|
|
(LockData.ddRVal == DDERR_WASSTILLDRAWING));
|
|
}
|
|
|
|
if ((dwTmp == DDHAL_DRIVER_NOTHANDLED) ||
|
|
(LockData.ddRVal == DD_OK))
|
|
{
|
|
// We successfully did the lock!
|
|
//
|
|
// If this is the primary surface and no window has been
|
|
// associated with the surface via DdResetVisRgn, then
|
|
// we have to force a redraw at Unlock time if any
|
|
// VisRgn has changed since the first Lock.
|
|
//
|
|
// If there is a window associated with the surface, then
|
|
// we have already checked that peSurface->iVisRgnUniqueness
|
|
// == po.iVisRgnUniqueness().
|
|
|
|
if (peSurface->cLocks++ == 0)
|
|
{
|
|
// If the surface is driver managed, we don't bother to
|
|
// increment the global lock count since we don't want to break
|
|
// locks when "losing" surfaces.
|
|
|
|
if (!(peSurface->dwFlags & DDRAWISURF_DRIVERMANAGED) ||
|
|
((peSurface->dwFlags & DDRAWISURF_DRIVERMANAGED) &&
|
|
(peSurface->ddsCapsEx.dwCaps2 & DDSCAPS2_DONOTPERSIST)))
|
|
{
|
|
peDdGlobalDriver->cSurfaceLocks++;
|
|
}
|
|
|
|
peSurface->iVisRgnUniqueness = VISRGN_UNIQUENESS();
|
|
}
|
|
else
|
|
{
|
|
if (peSurface->rclLock.left < LockData.rArea.left)
|
|
LockData.rArea.left = peSurface->rclLock.left;
|
|
|
|
if (peSurface->rclLock.top < LockData.rArea.top)
|
|
LockData.rArea.top = peSurface->rclLock.top;
|
|
|
|
if (peSurface->rclLock.right > LockData.rArea.right)
|
|
LockData.rArea.right = peSurface->rclLock.right;
|
|
|
|
if (peSurface->rclLock.bottom > LockData.rArea.bottom)
|
|
LockData.rArea.bottom = peSurface->rclLock.bottom;
|
|
}
|
|
|
|
// If this is the primary surface, then union the current DirectDraw
|
|
// bounds rectangle with the lock area rectangle.
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_PRIMARY)
|
|
{
|
|
if (peDdGlobalDriver->fl & DD_GLOBAL_FLAG_BOUNDS_SET)
|
|
{
|
|
if (LockData.rArea.left < peDdGlobalDriver->rclBounds.left)
|
|
peDdGlobalDriver->rclBounds.left = LockData.rArea.left;
|
|
|
|
if (LockData.rArea.top < peDdGlobalDriver->rclBounds.top)
|
|
peDdGlobalDriver->rclBounds.top = LockData.rArea.top;
|
|
|
|
if (LockData.rArea.right > peDdGlobalDriver->rclBounds.right)
|
|
peDdGlobalDriver->rclBounds.right = LockData.rArea.right;
|
|
|
|
if (LockData.rArea.bottom > peDdGlobalDriver->rclBounds.bottom)
|
|
peDdGlobalDriver->rclBounds.bottom = LockData.rArea.bottom;
|
|
}
|
|
else
|
|
{
|
|
peDdGlobalDriver->rclBounds = LockData.rArea;
|
|
peDdGlobalDriver->fl |= DD_GLOBAL_FLAG_BOUNDS_SET;
|
|
}
|
|
}
|
|
|
|
// If there was a flip pending, then there is not now.
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_FLIP_PENDING)
|
|
{
|
|
peSurface->fl &= ~DD_SURFACE_FLAG_FLIP_PENDING;
|
|
}
|
|
|
|
// Stash away surface lock data:
|
|
|
|
peSurface->rclLock = LockData.rArea;
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_PRIMARY)
|
|
{
|
|
if (peSurface->cLocks == 1)
|
|
{
|
|
// Add this surface to the head of the locked list:
|
|
|
|
peSurface->peSurface_PrimaryLockNext
|
|
= peDdGlobalDriver->peSurface_PrimaryLockList;
|
|
peDdGlobalDriver->peSurface_PrimaryLockList
|
|
= peSurface;
|
|
}
|
|
|
|
// If this is the primary surface, tear down any
|
|
// sprites that intersect with the specified
|
|
// rectangle:
|
|
|
|
if (DxEngSpTearDownSprites(peDdGlobalDriver->hdev,
|
|
&LockData.rArea,
|
|
TRUE))
|
|
{
|
|
// Here's some weirdness for you. That sprite
|
|
// tear-down we just did may have involved
|
|
// accelerator operations, which means the
|
|
// accelerator may be still in use if we
|
|
// immediately returned to the application,
|
|
// which of course is bad.
|
|
//
|
|
// You might think that a fix to this would
|
|
// be to put the sprite tear-down *before*
|
|
// the call to the driver's DdLock routine.
|
|
// But then you get the problem that DdLock
|
|
// would *always* return DDERR_WASSTILLDRAWING,
|
|
// and we would have to re-draw the sprites,
|
|
// meaning that the application would get into
|
|
// an endless loop if it was itself (like all
|
|
// of DirectDraw's HAL code) looping on
|
|
// DDERR_WASSTILLDRAWING.
|
|
//
|
|
// To solve this problem, we'll simply wait for
|
|
// accelerator idle after tearing-down the
|
|
// sprite. We do this by calling DdLock/DdUnlock
|
|
// again:
|
|
|
|
if (peDdGlobalDriver->SurfaceCallBacks.dwFlags
|
|
& DDHAL_SURFCB32_LOCK)
|
|
{
|
|
do
|
|
{
|
|
dwRedraw = peDdGlobalDriver->
|
|
SurfaceCallBacks.Lock(&LockData);
|
|
} while ((dwRedraw == DDHAL_DRIVER_HANDLED) &&
|
|
(LockData.ddRVal == DDERR_WASSTILLDRAWING));
|
|
}
|
|
|
|
if (peDdGlobalDriver->SurfaceCallBacks.dwFlags
|
|
& DDHAL_SURFCB32_UNLOCK)
|
|
{
|
|
UnlockData.lpDD = peDdGlobalDriver;
|
|
UnlockData.lpDDSurface = peSurface;
|
|
|
|
peDdGlobalDriver->
|
|
SurfaceCallBacks.Unlock(&UnlockData);
|
|
}
|
|
}
|
|
}
|
|
|
|
LockData.ddRVal = DD_OK;
|
|
|
|
if (dwTmp == DDHAL_DRIVER_HANDLED)
|
|
{
|
|
// If it says it handled the call, the driver is
|
|
// expected to have computed the address in the
|
|
// client's address space:
|
|
|
|
pvRet = (VOID*) LockData.lpSurfData;
|
|
|
|
ASSERTGDI(pvRet != NULL,
|
|
"Expected non-NULL lock pointer value (DRIVER_HANDLED)");
|
|
ASSERTGDI(pvRet < (PVOID) MM_USER_PROBE_ADDRESS,
|
|
"Expected user-mode lock pointer value (DRIVER_HANDLED)");
|
|
}
|
|
else
|
|
{
|
|
if (peSurface->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM)
|
|
{
|
|
pvRet = (VOID*)peSurface->fpVidMem;
|
|
}
|
|
else
|
|
{
|
|
pvRet = (VOID*) (peDirectDrawLocal->fpProcess
|
|
+ peSurface->fpVidMem);
|
|
}
|
|
|
|
ASSERTGDI(pvRet != NULL,
|
|
"Expected non-NULL lock pointer value (DRIVER_NOT_HANDLED)");
|
|
ASSERTGDI(pvRet < (PVOID) MM_USER_PROBE_ADDRESS,
|
|
"Expected user-mode lock pointer value (DRIVER_NOT_HANDLED)");
|
|
|
|
// DirectDraw has a goofy convention that when a
|
|
// driver returns DD_OK and DDHAL_DRIVER_HANDLED
|
|
// from a Lock, that the driver is also supposed to
|
|
// adjust the pointer to point to the upper left
|
|
// corner of the specified rectangle.
|
|
//
|
|
// This doesn't make a heck of a lot of sense for
|
|
// odd formats such as YUV surfaces, but oh well --
|
|
// since kernel-mode is acting like a driver to
|
|
// user-mode DirectDraw, we have to do the adjustment:
|
|
|
|
if (bHasRect)
|
|
{
|
|
pvRet = (VOID*)
|
|
((BYTE*) pvRet
|
|
+ (pArea->top * peSurface->lPitch)
|
|
+ (pArea->left
|
|
* (peSurface->ddpfSurface.dwRGBBitCount >> 3)));
|
|
}
|
|
}
|
|
|
|
// If this was an "aliased" lock, we store the corresponding pointer
|
|
// to the EDD_VMEMMAPPING
|
|
if (dwFlags & DDLOCK_NOSYSLOCK)
|
|
{
|
|
if (!(peSurface->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM))
|
|
{
|
|
peSurface->peMap = peDirectDrawLocal->peMapCurrent;
|
|
|
|
ASSERTGDI(peSurface->peMap != NULL,
|
|
"Expected video memory to be mapped into user space");
|
|
}
|
|
else
|
|
{
|
|
// If the non-local surface was not allocated from one of
|
|
// our managed heaps, then lpVidMemHeap will be NULL and
|
|
// we cannot alias the heap, so we don't do the aliased
|
|
// lock.
|
|
|
|
if (peSurface->lpVidMemHeap != NULL)
|
|
{
|
|
peSurface->peMap = peDirectDrawLocal->ppeMapAgp[
|
|
(peSurface->lpVidMemHeap -
|
|
peDdGlobalDriver->pvmList)];
|
|
}
|
|
}
|
|
|
|
// If the map pointer is NULL, then the surface lock cannot be
|
|
// aliased so proceed as if DDLOCK_NOSYSLOCK was not passed.
|
|
// Otherwise, take the appropriate reference counts now:
|
|
|
|
if (peSurface->peMap != NULL)
|
|
{
|
|
peSurface->fl |= DD_SURFACE_FLAG_ALIAS_LOCK;
|
|
peDdGlobalDriver->cSurfaceAliasedLocks++;
|
|
peSurface->peMap->cReferences++;
|
|
// Keep a reference of the driver instance used to create this mapping
|
|
peSurface->peVirtualMapDdGlobal = peDdGlobalDriver;
|
|
vDdIncrementReferenceCount(peDdGlobalDriver);
|
|
DDKHEAP(("Taken aliased lock: peSurface=%lx, peMap=%lx, "
|
|
"peDdGlobalDriver=%lx\n",
|
|
peSurface, peSurface->peMap, peDdGlobalDriver));
|
|
}
|
|
else
|
|
{
|
|
// We have a private driver cap that will enable us to treat
|
|
// AGP surface locks as aliased even though the driver doesn't
|
|
// expose an AGP heap. This is to enable drivers to work around
|
|
// anything that we happen to do wrong in our AGP code without
|
|
// them incurring the 7 second tiemout on every mode change.
|
|
|
|
if ((peSurface->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM) &&
|
|
(peDdGlobalDriver->PrivateCaps.dwPrivateCaps & DDHAL_PRIVATECAP_RESERVED1))
|
|
|
|
{
|
|
peSurface->fl |= DD_SURFACE_FLAG_ALIAS_LOCK;
|
|
peDdGlobalDriver->cSurfaceAliasedLocks++;
|
|
peSurface->fl |= DD_SURFACE_FLAG_FAKE_ALIAS_LOCK;
|
|
}
|
|
|
|
// Just to avoid possible problems in the future, turn
|
|
// off the flag here:
|
|
|
|
dwFlags &= ~DDLOCK_NOSYSLOCK;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (LockData.ddRVal != DDERR_WASSTILLDRAWING)
|
|
{
|
|
WARNING("pDdLockSurface: Driver failed DdLock\n");
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
if (pResult)
|
|
{
|
|
*pResult = LockData.ddRVal;
|
|
}
|
|
|
|
return(pvRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdUnlockSurfaceOrBuffer
|
|
*
|
|
* DirectDraw unlock for surfaces and D3D buffers.
|
|
*
|
|
* Note that the Devlock MUST NOT be held when entering this function
|
|
* if the surface is the primary surface.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdUnlockSurfaceOrBuffer(
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
BOOL b;
|
|
BOOL bRedraw;
|
|
BOOL bFreeVirtualMap = FALSE;
|
|
EDD_DIRECTDRAW_GLOBAL *peDdGlobalDriver;
|
|
|
|
if (peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
peSurface->fl &= ~DD_SURFACE_FLAG_ALIAS_LOCK;
|
|
b = FALSE;
|
|
bRedraw = FALSE;
|
|
|
|
{
|
|
// Don't hold ShareLock togather (see vDdDisableAllDirectDrawObjects)
|
|
// Give a change to signal AssertMode event.
|
|
|
|
EDD_DEVLOCK eDevlock(peSurface->peDirectDrawGlobal);
|
|
|
|
// Due to video mode change across different video driver, currently
|
|
// this "driver managed" surface is associated to different driver
|
|
// than the driver who actually manage it. So we must call the driver
|
|
// which actually manage the surface.
|
|
//
|
|
// peSurface->fl can be changed by mode change, thus we access there
|
|
// under holding devlock.
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_WRONG_DRIVER)
|
|
{
|
|
// If surface is owned by different driver, lock right driver.
|
|
|
|
if (peSurface->peDirectDrawGlobal != peSurface->peDdGlobalCreator)
|
|
{
|
|
// Unlike DdLockSurfaceOrBuffer case, we can't just unlock and
|
|
// lock with new device. Because, we can't hold sharelock (see above)
|
|
// so when we unlock device, there is a chance to mode change happens.
|
|
// thus, after we relock the device, we have to make sure peDdGlobalCreator
|
|
// is continue to be save as before. Otherwise loop until it match.
|
|
|
|
do {
|
|
peDdGlobalDriver = peSurface->peDdGlobalCreator;
|
|
eDevlock.vUnlockDevice();
|
|
eDevlock.vUpdateDevice(peDdGlobalDriver);
|
|
eDevlock.vLockDevice();
|
|
} while (peDdGlobalDriver !=
|
|
((EDD_DIRECTDRAW_GLOBAL volatile *)(peSurface->peDdGlobalCreator)));
|
|
|
|
// WARNING("pDdLockSurfaceOrBuffer: Unlock on wrong driver");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
peDdGlobalDriver = peSurface->peDirectDrawGlobal;
|
|
}
|
|
|
|
// Make sure there was a previous lock:
|
|
|
|
if (peSurface->cLocks > 0)
|
|
{
|
|
if ((peSurface->dwFlags & DDRAWISURF_DRIVERMANAGED) &&
|
|
!(peSurface->ddsCapsEx.dwCaps2 & DDSCAPS2_DONOTPERSIST))
|
|
{
|
|
// Driver managed surface can be unlock ANYTIME.
|
|
// (even PDEV is disabled)
|
|
}
|
|
else
|
|
{
|
|
PDEVOBJ po(peDdGlobalDriver->hdev);
|
|
|
|
ASSERTGDI(!po.bDisabled(),
|
|
"Surface is disabled but there are outstanding locks?");
|
|
}
|
|
|
|
vDdRelinquishSurfaceOrBufferLock(peDdGlobalDriver, peSurface);
|
|
|
|
// Does lock went to 0 after "Relinquish" ?
|
|
|
|
if (peSurface->cLocks == 0)
|
|
{
|
|
// Was this an aliased lock ?
|
|
|
|
if (peSurface->peMap)
|
|
{
|
|
bFreeVirtualMap = TRUE;
|
|
}
|
|
|
|
// If the API-disabled flag is set and we got this far into
|
|
// Unlock, it means that there is a DdSuspendDirectDraw()
|
|
// call pending, and that thread is waiting for all surface
|
|
// locks related to the device to be released.
|
|
//
|
|
// If this is the last lock to be released, signal the event
|
|
// so that the AssertMode thread can continue on.
|
|
|
|
if ((peDdGlobalDriver->cSurfaceLocks == 0) &&
|
|
(peDdGlobalDriver->bSuspended))
|
|
{
|
|
KeSetEvent(peDdGlobalDriver->pAssertModeEvent,
|
|
0,
|
|
FALSE);
|
|
}
|
|
|
|
// NOTE: This should really test if the surface has a clipper. But
|
|
// it can't because of comapatibility with Win95, where
|
|
// applications expect a primary surface lock to be atomic
|
|
// even if they haven't attached a clipper object.
|
|
// (Microsoft's own OPENGL32.DLL does this, that shipped
|
|
// in NT 5.0.) However, this means that applications
|
|
// that are full-screen double buffering can possibly
|
|
// be causing a whole bunch of repaints when it does a
|
|
// direct lock on (what is now) the back buffer.
|
|
//
|
|
// Potentially, this 'if' should have an additional
|
|
// condition, and that is not to do it if the application
|
|
// is in exclusive mode:
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_PRIMARY)
|
|
{
|
|
// If the VisRgn changed while the application was writing
|
|
// to the surface, it may have started drawing over the
|
|
// the wrong window, so fix it up.
|
|
//
|
|
// Alas, right now a DirectDraw application doesn't always
|
|
// tell us what window it was drawing to, so we can't fix
|
|
// up only the affected windows. Instead, we solve it the
|
|
// brute-force way and redraw *all* windows:
|
|
|
|
if (peSurface->iVisRgnUniqueness != VISRGN_UNIQUENESS())
|
|
{
|
|
// We can't call UserRedrawDesktop here because it
|
|
// grabs the User critical section, and we're already
|
|
// holding the devlock -- which could cause a possible
|
|
// deadlock. Since it's a posted message it obviously
|
|
// doesn't have to be done under the devlock.
|
|
|
|
bRedraw = TRUE;
|
|
|
|
// Note that we should not update peSurface->
|
|
// iVisRgnUniqueness here. That's because if the
|
|
// application has attached a window to the surface, it
|
|
// has to be notified that the clipping has changed --
|
|
// which is done by returning DDERR_VISRGNCHANGED on the
|
|
// next Lock or Blt call. And if the application has
|
|
// not attached a window, we automatically update the
|
|
// uniqueness at the next Lock time.
|
|
}
|
|
}
|
|
}
|
|
|
|
b = TRUE;
|
|
}
|
|
else // if (peSurface->cLocks == 0)
|
|
{
|
|
// The lock count is 0 but we may have a "broken" lock.
|
|
if (peSurface->peMap)
|
|
{
|
|
bFreeVirtualMap = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("bDdUnlockSurfaceOrBuffer: Surface already unlocked\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bRedraw)
|
|
{
|
|
PDEVOBJ po(peDdGlobalDriver->hdev);
|
|
|
|
// We can redraw only if we're not holding the devlock, because
|
|
// User needs to acquire its critical section. The User lock
|
|
// must always be acquired before the devlock, which is why
|
|
// we can't call User if we're already holding the devlock.
|
|
//
|
|
// I don't trust any callers enough to merely assert that we're
|
|
// not holding the devlock; I'll actually check...
|
|
|
|
if (!DxEngIsHdevLockedByCurrentThread(po.hdev()))
|
|
{
|
|
DxEngRedrawDesktop();
|
|
}
|
|
}
|
|
|
|
if (bFreeVirtualMap)
|
|
{
|
|
// We can release virtual map if we're not holding the devlock,
|
|
// because it might release GDI's PDEV if this is last reference.
|
|
|
|
vDdReleaseVirtualMap(peSurface);
|
|
}
|
|
|
|
return(b);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HANDLE DxDdCreateDirectDrawObject
|
|
*
|
|
* Creates a DirectDraw object.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HANDLE
|
|
APIENTRY
|
|
DxDdCreateDirectDrawObject(
|
|
HDC hdc
|
|
)
|
|
{
|
|
HANDLE hDirectDrawLocal;
|
|
|
|
hDirectDrawLocal = 0; // Assume failure
|
|
|
|
PVOID pvLockedDC = DxEngLockDC(hdc);
|
|
|
|
if (pvLockedDC)
|
|
{
|
|
PDEVOBJ po((HDEV)DxEngGetDCState(hdc,DCSTATE_HDEV));
|
|
|
|
if (po.bValid() && po.bDisplayPDEV())
|
|
{
|
|
// Note that we aren't checking to see if the PDEV is disabled,
|
|
// so that DirectDraw could be started even when full-screen:
|
|
|
|
EDD_DEVLOCK eDevlock(po.hdev());
|
|
|
|
if (!(po.bDisabled()))
|
|
{
|
|
CheckAgpHeaps(po.peDirectDrawGlobal());
|
|
}
|
|
|
|
// DirectDraw works only at 8bpp or higher:
|
|
|
|
if (po.iDitherFormat() >= BMF_8BPP)
|
|
{
|
|
hDirectDrawLocal = hDdCreateDirectDrawLocal(po);
|
|
}
|
|
}
|
|
|
|
DxEngUnlockDC(pvLockedDC);
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdCreateDirectDrawObject: Bad DC\n");
|
|
}
|
|
|
|
return(hDirectDrawLocal);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DxDdDeleteDirectDrawObject
|
|
*
|
|
* Deletes a kernel-mode representation of the surface.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
APIENTRY
|
|
DxDdDeleteDirectDrawObject(
|
|
HANDLE hDirectDrawLocal
|
|
)
|
|
{
|
|
return(bDdDeleteDirectDrawObject(hDirectDrawLocal, FALSE));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HANDLE DxDdQueryDirectDrawObject
|
|
*
|
|
* Queries a DirectDraw object.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
APIENTRY
|
|
DxDdQueryDirectDrawObject(
|
|
HANDLE hDirectDrawLocal,
|
|
DD_HALINFO* pHalInfo,
|
|
DWORD* pCallBackFlags,
|
|
LPD3DNTHAL_CALLBACKS puD3dCallbacks,
|
|
LPD3DNTHAL_GLOBALDRIVERDATA puD3dDriverData,
|
|
PDD_D3DBUFCALLBACKS puD3dBufferCallbacks,
|
|
LPDDSURFACEDESC puD3dTextureFormats,
|
|
DWORD* puNumHeaps,
|
|
VIDEOMEMORY* puvmList,
|
|
DWORD* puNumFourCC,
|
|
DWORD* puFourCC
|
|
)
|
|
{
|
|
BOOL b;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
ULONG cBytes;
|
|
|
|
b = FALSE; // Assume failure
|
|
|
|
// The most fundamental basis of accelerated DirectDraw is that it
|
|
// allows direct access to the frame buffer by the application. If
|
|
// security permissions prohibit reading from the screen, we cannot
|
|
// allow accelerated DirectDraw:
|
|
|
|
if (DxEngScreenAccessCheck())
|
|
{
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDrawLocal);
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
// A registry timeout value of 'zero' signifies that DirectDraw
|
|
// accelerations cannot be enabled. Note that the timeout is
|
|
// non-positive because it's a relative time duration.
|
|
|
|
if (peDirectDrawGlobal->llAssertModeTimeout < 0)
|
|
{
|
|
DWORD dwOverride;
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
// Get driver override info:
|
|
|
|
dwOverride = po.dwDriverCapableOverride();
|
|
|
|
__try
|
|
{
|
|
DD_HALINFO ddhi = peDirectDrawGlobal->HalInfo;
|
|
|
|
if ( dwOverride & DRIVER_NOT_CAPABLE_D3D )
|
|
{
|
|
// If the driver is not capable of doing D3D, turn the CAPS
|
|
// off
|
|
|
|
ddhi.ddCaps.dwCaps &= ~DDCAPS_3D;
|
|
ddhi.lpD3DGlobalDriverData = 0;
|
|
ddhi.lpD3DHALCallbacks = 0;
|
|
}
|
|
|
|
#ifdef DX_REDIRECTION
|
|
if ( gbDxRedirection )
|
|
{
|
|
// If we are in redirection mode, disable overlay.
|
|
|
|
ddhi.ddCaps.dwCaps &= ~DDCAPS_OVERLAY;
|
|
ddhi.ddCaps.dwMaxVisibleOverlays = 0;
|
|
}
|
|
#endif // DX_REDIRECTION
|
|
|
|
ProbeAndWriteStructure(pHalInfo,
|
|
ddhi,
|
|
DD_HALINFO);
|
|
|
|
ProbeForWrite(pCallBackFlags, 3 * sizeof(ULONG), sizeof(ULONG));
|
|
pCallBackFlags[0] = peDirectDrawGlobal->CallBacks.dwFlags;
|
|
pCallBackFlags[1] = peDirectDrawGlobal->SurfaceCallBacks.dwFlags;
|
|
pCallBackFlags[2] = peDirectDrawGlobal->PaletteCallBacks.dwFlags;
|
|
|
|
if (puD3dCallbacks != NULL)
|
|
{
|
|
ProbeAndWriteStructure(puD3dCallbacks,
|
|
peDirectDrawGlobal->D3dCallBacks,
|
|
D3DNTHAL_CALLBACKS);
|
|
}
|
|
|
|
if (puD3dDriverData != NULL)
|
|
{
|
|
ProbeAndWriteStructure(puD3dDriverData,
|
|
peDirectDrawGlobal->D3dDriverData,
|
|
D3DNTHAL_GLOBALDRIVERDATA);
|
|
}
|
|
|
|
if (puD3dBufferCallbacks != NULL)
|
|
{
|
|
ProbeAndWriteStructure(puD3dBufferCallbacks,
|
|
peDirectDrawGlobal->D3dBufCallbacks,
|
|
DD_D3DBUFCALLBACKS);
|
|
}
|
|
|
|
if (puD3dTextureFormats != NULL)
|
|
{
|
|
ProbeForWrite(puD3dTextureFormats,
|
|
peDirectDrawGlobal->D3dDriverData.dwNumTextureFormats*
|
|
sizeof(DDSURFACEDESC), sizeof(DWORD));
|
|
RtlCopyMemory(puD3dTextureFormats,
|
|
peDirectDrawGlobal->D3dDriverData.lpTextureFormats,
|
|
peDirectDrawGlobal->D3dDriverData.dwNumTextureFormats*
|
|
sizeof(DDSURFACEDESC));
|
|
}
|
|
|
|
ProbeAndWriteUlong(puNumFourCC, peDirectDrawGlobal->dwNumFourCC);
|
|
|
|
// Offscreen heap allocations are handled directly
|
|
// in the kernel so don't report any memory back to
|
|
// user mode.
|
|
|
|
ProbeAndWriteUlong(puNumHeaps, 0);
|
|
|
|
if (puFourCC != NULL)
|
|
{
|
|
cBytes = sizeof(ULONG) * peDirectDrawGlobal->dwNumFourCC;
|
|
|
|
ProbeForWrite(puFourCC, cBytes, sizeof(ULONG));
|
|
RtlCopyMemory(puFourCC, peDirectDrawGlobal->pdwFourCC, cBytes);
|
|
}
|
|
|
|
b = TRUE;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("DxDdQueryDirectDrawObject: Passed bad pointers\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdQueryDirectDrawObject: DirectDraw disabled in registry\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdQueryDirectDrawObject: Bad handle or busy\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdCreateDirectDrawObject: Don't have screen read permission");
|
|
}
|
|
|
|
return(b);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* EDD_SURFACE* peDdOpenNewSurfaceObject
|
|
*
|
|
* Creates a new kernel-mode surface by re-using the old surface if it's
|
|
* lost, or by allocating a new surface.
|
|
*
|
|
* NOTE: Leaves the surface exclusive locked!
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
EDD_SURFACE*
|
|
peDdOpenNewSurfaceObject(
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal,
|
|
HANDLE hSurface,
|
|
DD_SURFACE_GLOBAL* pSurfaceGlobal,
|
|
DD_SURFACE_LOCAL* pSurfaceLocal,
|
|
DD_SURFACE_MORE* pSurfaceMore
|
|
)
|
|
{
|
|
EDD_SURFACE* peSurface;
|
|
|
|
BOOL bSurfaceAlloced = FALSE;
|
|
|
|
// First, try to resurrect the old surface if there is one:
|
|
|
|
peSurface = NULL;
|
|
if (hSurface != 0)
|
|
{
|
|
peSurface = (EDD_SURFACE*) DdHmgLock((HDD_OBJ) hSurface, DD_SURFACE_TYPE, FALSE);
|
|
if (peSurface == NULL)
|
|
{
|
|
WARNING("peDdOpenNewSurfaceObject: hDDSurface wasn't set to 0\n");
|
|
}
|
|
else if ((peSurface->peDirectDrawLocal != peDirectDrawLocal) ||
|
|
(!(peSurface->bLost)))
|
|
{
|
|
WARNING("peDdOpenNewSurfaceObject: Couldn't re-use surface\n");
|
|
DEC_EXCLUSIVE_REF_CNT(peSurface);
|
|
peSurface = NULL;
|
|
return(peSurface);
|
|
}
|
|
|
|
#if DBG
|
|
if (peSurface != NULL)
|
|
{
|
|
DDKSURF(("DDKSURF: Reusing %X (%X)\n", hSurface, peSurface));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (peSurface == NULL)
|
|
{
|
|
peSurface = (EDD_SURFACE*) DdHmgAlloc(sizeof(EDD_SURFACE),
|
|
DD_SURFACE_TYPE,
|
|
HMGR_ALLOC_LOCK);
|
|
if (peSurface != NULL)
|
|
{
|
|
bSurfaceAlloced = TRUE;
|
|
|
|
// Win95's DirectDraw makes a number of allocations that represent
|
|
// a single surface, and have pointers between the different
|
|
// parts. We make just one allocation and so the pointers refer
|
|
// back to ourselves. Note that the power of C++ means that
|
|
// 'lpGbl = peSurface' assigns 'lpGbl' the address to the
|
|
// DD_SURFACE_GLOBAL part of 'peSurface':
|
|
|
|
peSurface->lpGbl = peSurface;
|
|
peSurface->lpSurfMore = peSurface;
|
|
peSurface->lpLcl = peSurface;
|
|
|
|
peSurface->peDirectDrawLocal = peDirectDrawLocal;
|
|
peSurface->peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
// Remember original creator of this surface (in case for video mode change).
|
|
|
|
PDEVOBJ po(peSurface->peDirectDrawGlobal->hdev);
|
|
|
|
// and remember which graphics device has association.
|
|
peSurface->pldevCreator = po.pldev(); // driver
|
|
peSurface->pGraphicsDeviceCreator = po.pGraphicsDevice(); // hardware
|
|
|
|
// No locks yet
|
|
peSurface->peMap = NULL;
|
|
|
|
// This is new surface, so it keeps lost state initially.
|
|
// The surface will be marked as lost until 'vDdCompleteSurfaceObject'
|
|
// is called on it:
|
|
|
|
peSurface->bLost = TRUE;
|
|
|
|
DDKSURF(("DDKSURF: Created %X (%X)\n", peSurface->hGet(), peSurface));
|
|
}
|
|
}
|
|
|
|
if ((peSurface != NULL) &&
|
|
!(peSurface->fl & DD_SURFACE_FLAG_CREATE_COMPLETE))
|
|
{
|
|
// We do this under try ~ except, because pSurfaceGlobal/Local/More
|
|
// could be user mode buffer.
|
|
|
|
__try
|
|
{
|
|
peSurface->fpVidMem = pSurfaceGlobal->fpVidMem;
|
|
peSurface->lPitch = pSurfaceGlobal->lPitch;
|
|
peSurface->wWidth = pSurfaceGlobal->wWidth;
|
|
peSurface->wHeight = pSurfaceGlobal->wHeight;
|
|
peSurface->wWidthOriginal = pSurfaceGlobal->wWidth;
|
|
peSurface->wHeightOriginal = pSurfaceGlobal->wHeight;
|
|
peSurface->ddpfSurface = pSurfaceGlobal->ddpfSurface;
|
|
peSurface->ddsCaps = pSurfaceLocal->ddsCaps;
|
|
// Copy just the driver managed flag
|
|
peSurface->dwFlags &= ~DDRAWISURF_DRIVERMANAGED;
|
|
peSurface->dwFlags |= (pSurfaceLocal->dwFlags & DDRAWISURF_DRIVERMANAGED);
|
|
peSurface->ddsCapsEx = pSurfaceMore->ddsCapsEx;
|
|
peSurface->dwSurfaceHandle = pSurfaceMore->dwSurfaceHandle;
|
|
// Copy the slice pitch for sysmem volume textures
|
|
if ((peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
(peSurface->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME))
|
|
{
|
|
peSurface->dwBlockSizeY = pSurfaceGlobal->dwBlockSizeY;
|
|
}
|
|
|
|
if (!(peSurface->bLost))
|
|
{
|
|
peSurface->bLost = TRUE;
|
|
|
|
// Surface wasn't losted formerly, but here we put null to make it lost forcely.
|
|
// This might causes some leak in driver, but anyway we should decrement
|
|
// active surface count here.
|
|
|
|
ASSERTGDI(peSurface->peDirectDrawLocal->cActiveSurface > 0,
|
|
"cActiveSurface will be negative");
|
|
|
|
peSurface->peDirectDrawLocal->cActiveSurface--;
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
if (bSurfaceAlloced)
|
|
{
|
|
DdFreeObject(peSurface, DD_SURFACE_TYPE);
|
|
}
|
|
else
|
|
{
|
|
DEC_EXCLUSIVE_REF_CNT(peSurface);
|
|
}
|
|
|
|
peSurface = NULL;
|
|
}
|
|
}
|
|
|
|
// if everything went fine, and this is newly allocated surface ...
|
|
|
|
if (peSurface && bSurfaceAlloced)
|
|
{
|
|
// Add this to the head of the surface list hanging off the
|
|
// local DirectDraw object.
|
|
//
|
|
// This list is protected because we have exclusive access to
|
|
// the local DirectDraw object:
|
|
|
|
InsertHeadList(&(peDirectDrawLocal->ListHead_eSurface),
|
|
&(peSurface->List_eSurface));
|
|
|
|
peDirectDrawLocal->cSurface++;
|
|
}
|
|
|
|
return(peSurface);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdValidateSurfaceDescription
|
|
*
|
|
* Validates surface description information.
|
|
* Can be used before surface actually exists to validate data
|
|
* prior to creation.
|
|
*
|
|
* 6-Feb-1998 -by- Drew Bliss [drewb]
|
|
* Split from bDdValidateSurfaceObject.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdValidateSurfaceDescription(
|
|
DD_SURFACE_GLOBAL* pSurfaceGlobal,
|
|
DD_SURFACE_LOCAL* pSurfaceLocal
|
|
)
|
|
{
|
|
// Protect against math overflow:
|
|
|
|
if (!(pSurfaceLocal->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
|
|
{
|
|
if ((pSurfaceGlobal->wWidth > DD_MAXIMUM_COORDINATE) ||
|
|
(pSurfaceGlobal->wWidth <= 0) ||
|
|
(pSurfaceGlobal->wHeight > DD_MAXIMUM_COORDINATE) ||
|
|
(pSurfaceGlobal->wHeight <= 0))
|
|
{
|
|
WARNING("bDdValidateSurfaceDescription: Bad dimensions");
|
|
return(FALSE);
|
|
}
|
|
|
|
// dwRGBBitCount is overloaded with dwYUVBitCount:
|
|
|
|
if ((pSurfaceGlobal->ddpfSurface.dwRGBBitCount < 1) &&
|
|
!(pSurfaceGlobal->ddpfSurface.dwFlags & DDPF_FOURCC))
|
|
{
|
|
WARNING("bDdValidateSurfaceDescription: Bad bit count");
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pSurfaceGlobal->ddpfSurface.dwFlags & DDPF_RGB)
|
|
{
|
|
if ((pSurfaceGlobal->ddpfSurface.dwRGBBitCount != 1) &&
|
|
(pSurfaceGlobal->ddpfSurface.dwRGBBitCount != 2) &&
|
|
(pSurfaceGlobal->ddpfSurface.dwRGBBitCount != 4) &&
|
|
(pSurfaceGlobal->ddpfSurface.dwRGBBitCount != 8) &&
|
|
(pSurfaceGlobal->ddpfSurface.dwRGBBitCount != 16) &&
|
|
(pSurfaceGlobal->ddpfSurface.dwRGBBitCount != 24) &&
|
|
(pSurfaceGlobal->ddpfSurface.dwRGBBitCount != 32))
|
|
{
|
|
WARNING("bDdValidateSurfaceDescription: "
|
|
"dwRGBBitCount not 1, 2, 4, 8, 16, 24 or 32");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdValidateSystemMemoryObject
|
|
*
|
|
* Checks surface description and parameters for an existing
|
|
* system-memory surface.
|
|
*
|
|
* Checks suitable for pre-creation testing should be in
|
|
* bDdValidateSurfaceDescription.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdValidateSystemMemoryObject(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
if (!bDdValidateSurfaceDescription(peSurface, peSurface))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (!(peSurface->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
|
|
{
|
|
if (ABS(peSurface->lPitch) > 4 * DD_MAXIMUM_COORDINATE)
|
|
{
|
|
WARNING("bDdValidateSurfaceObject: Bad dimensions");
|
|
return(FALSE);
|
|
}
|
|
|
|
// The width in bytes must not be more than the pitch.
|
|
|
|
if (peSurface->wWidth * peSurface->ddpfSurface.dwRGBBitCount >
|
|
(ULONG) 8 * ABS(peSurface->lPitch))
|
|
{
|
|
WARNING("bDdValidateSurfaceObject: Bad pitch");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
if ((peSurface->fpVidMem & 3) || (peSurface->lPitch & 3))
|
|
{
|
|
WARNING("bDdValidateSurfaceObject: Bad alignment");
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdSecureSystemMemorySurface
|
|
*
|
|
* For system-memory surfaces, the user-mode DirectDraw component allocates
|
|
* the actual bits for storage. Since we will need to access those bits
|
|
* from kernel mode for the duration of the life of the surface, we must
|
|
* ensure that they're valid user-mode bits and that the pages will never
|
|
* be decommitted until the kernel-mode surface is destroyed.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdSecureSystemMemorySurface(
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
FLATPTR fpStart;
|
|
FLATPTR fpEnd;
|
|
DWORD dwHeight;
|
|
|
|
// Note that bDdValidateSurfaceObject has already ensured that
|
|
// lPitch, fpVidMem, and the dimensions are "reasonable".
|
|
|
|
if (!(peSurface->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
|
|
{
|
|
dwHeight = peSurface->wHeight;
|
|
}
|
|
else
|
|
{
|
|
dwHeight = 1;
|
|
}
|
|
|
|
|
|
if (peSurface->lPitch >= 0)
|
|
{
|
|
fpStart = peSurface->fpVidMem;
|
|
fpEnd = fpStart + dwHeight * peSurface->lPitch;
|
|
}
|
|
else
|
|
{
|
|
fpEnd = peSurface->fpVidMem - peSurface->lPitch;
|
|
fpStart = fpEnd + dwHeight * peSurface->lPitch;
|
|
}
|
|
|
|
|
|
ASSERTGDI(fpEnd >= fpStart, "Messed up fpStart and fpEnd");
|
|
|
|
__try
|
|
{
|
|
ProbeForWrite((VOID*) fpStart, (ULONG)(ULONG_PTR)((BYTE*)fpEnd - (BYTE*)fpStart),
|
|
sizeof(DWORD));
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("bDdSecureSystemMemorySurface: fpVidMem wasn't valid and writable");
|
|
return(FALSE);
|
|
}
|
|
|
|
peSurface->hSecure = MmSecureVirtualMemory((VOID*) fpStart,
|
|
fpEnd - fpStart,
|
|
PAGE_READWRITE);
|
|
|
|
return(peSurface->hSecure != 0);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdCompleteSurfaceObject
|
|
*
|
|
* Add the object to the surface list and initialize some miscellaneous
|
|
* fields.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vDdCompleteSurfaceObject(
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal,
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
FLATPTR fpStartOffset;
|
|
LONG lDisplayPitch;
|
|
DWORD dwDepth;
|
|
DWORD dwBitsPixel;
|
|
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
// Calculate the 2-d coordinate 'hint' for 2-d cards so that
|
|
// hopefully they don't need to do these three divides each
|
|
// time they need to use the surface:
|
|
|
|
if (peSurface->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM)
|
|
{
|
|
dwBitsPixel = peSurface->ddpfSurface.dwRGBBitCount;
|
|
|
|
if ((dwBitsPixel > 0) && (peSurface->lpVidMemHeap != NULL))
|
|
{
|
|
fpStartOffset =
|
|
peSurface->fpHeapOffset - peSurface->lpVidMemHeap->fpStart;
|
|
|
|
if (peSurface->lpVidMemHeap->dwFlags & VMEMHEAP_RECTANGULAR)
|
|
{
|
|
lDisplayPitch = peSurface->lpVidMemHeap->lpHeap->stride;
|
|
}
|
|
else
|
|
{
|
|
lDisplayPitch = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fpStartOffset = 0;
|
|
lDisplayPitch = 1;
|
|
dwBitsPixel = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fpStartOffset = peSurface->fpVidMem
|
|
- peDirectDrawGlobal->HalInfo.vmiData.fpPrimary;
|
|
lDisplayPitch = peDirectDrawGlobal->HalInfo.vmiData.lDisplayPitch;
|
|
dwBitsPixel =
|
|
peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount;
|
|
}
|
|
|
|
peSurface->yHint = (LONG) (fpStartOffset / lDisplayPitch);
|
|
peSurface->xHint =
|
|
(LONG) (8 * (fpStartOffset % lDisplayPitch) / dwBitsPixel);
|
|
|
|
// Make sure some other flags are correct:
|
|
|
|
peSurface->ddsCaps.dwCaps &= ~DDSCAPS_PRIMARYSURFACE;
|
|
if (peSurface->fl & DD_SURFACE_FLAG_PRIMARY)
|
|
{
|
|
peSurface->ddsCaps.dwCaps |= DDSCAPS_PRIMARYSURFACE;
|
|
}
|
|
|
|
// Remember who is creator (needed for driver managed surface).
|
|
|
|
peSurface->peDdGlobalCreator = peDirectDrawGlobal;
|
|
|
|
// And if this is driver managed surface, keep reference on driver.
|
|
|
|
if (peSurface->dwFlags & DDRAWISURF_DRIVERMANAGED)
|
|
{
|
|
ASSERTGDI(peSurface->fl & DD_SURFACE_FLAG_DRIVER_CREATED,
|
|
"vDdCompleteSurfaceObject: driver managed surface must be driver created.");
|
|
|
|
vDdIncrementReferenceCount(peDirectDrawGlobal);
|
|
}
|
|
|
|
// This denotes, among other things, that the surface has been added
|
|
// to the surface list, so on deletion it will have to ben removed
|
|
// from the surface list:
|
|
|
|
peSurface->fl |= DD_SURFACE_FLAG_CREATE_COMPLETE;
|
|
|
|
// We've had stress failures where there is some funky reuse of the
|
|
// surfaces and we assert because the hbmGdi wasn't cleaned up. We
|
|
// do it here since we're on the same process as a final check.
|
|
|
|
if (peSurface->hbmGdi)
|
|
{
|
|
DxEngDeleteSurface( (HSURF) peSurface->hbmGdi);
|
|
peSurface->hbmGdi = NULL;
|
|
|
|
if (peSurface->hpalGdi)
|
|
{
|
|
EngDeletePalette(peSurface->hpalGdi);
|
|
peSurface->hpalGdi = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HANDLE DxDdCreateSurfaceObject
|
|
*
|
|
* Creates a kernel-mode representation of the surface, given a location
|
|
* in off-screen memory allocated by user-mode DirectDraw.
|
|
*
|
|
* We expect DirectDraw to already have called DxDdCreateSurface, which
|
|
* gives the driver a chance at creating the surface. In the future, I expect
|
|
* all off-screen memory management to be moved to the kernel, with all surface
|
|
* allocations being handled via DxDdCreateSurface. This function call will
|
|
* then be extraneous.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HANDLE
|
|
APIENTRY
|
|
DxDdCreateSurfaceObject(
|
|
HANDLE hDirectDrawLocal,
|
|
HANDLE hSurface,
|
|
PDD_SURFACE_LOCAL puSurfaceLocal,
|
|
PDD_SURFACE_MORE puSurfaceMore,
|
|
PDD_SURFACE_GLOBAL puSurfaceGlobal,
|
|
BOOL bComplete // TRUE if surface is now complete.
|
|
// FALSE if we're just creating a
|
|
// kernel handle to handle attaches;
|
|
// the surface will be filled-out
|
|
// and 'completed' in a later call
|
|
) // to DxDdCreateSurfaceObject.
|
|
{
|
|
HANDLE hRet;
|
|
DD_SURFACE_LOCAL SurfaceLocal;
|
|
DD_SURFACE_MORE SurfaceMore;
|
|
DD_SURFACE_GLOBAL SurfaceGlobal;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_SURFACE* peSurface;
|
|
|
|
hRet = 0;
|
|
|
|
__try
|
|
{
|
|
SurfaceLocal = ProbeAndReadStructure(puSurfaceLocal, DD_SURFACE_LOCAL);
|
|
SurfaceMore = ProbeAndReadStructure(puSurfaceMore, DD_SURFACE_MORE);
|
|
SurfaceGlobal = ProbeAndReadStructure(puSurfaceGlobal, DD_SURFACE_GLOBAL);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(hRet);
|
|
}
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDrawLocal);
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
if (SurfaceLocal.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
// This is system memory
|
|
|
|
peSurface = peDdOpenNewSurfaceObject(peDirectDrawLocal,
|
|
hSurface,
|
|
&SurfaceGlobal,
|
|
&SurfaceLocal,
|
|
&SurfaceMore);
|
|
if (peSurface)
|
|
{
|
|
if (bComplete)
|
|
{
|
|
if ((bDdValidateSystemMemoryObject(peDirectDrawGlobal,
|
|
peSurface)) &&
|
|
(bDdSecureSystemMemorySurface(peSurface)))
|
|
{
|
|
ASSERTGDI(peSurface->hbmGdi == NULL,
|
|
"DxDdCreateSurfaceObject: Invalid cached bitmap");
|
|
|
|
// If this surface is in lost state, make it active.
|
|
|
|
if (peSurface->bLost)
|
|
{
|
|
peSurface->bLost = FALSE;
|
|
|
|
// Now this surface is ready to go, increment active surface ref. count.
|
|
|
|
peSurface->peDirectDrawLocal->cActiveSurface++;
|
|
|
|
ASSERTGDI(peSurface->peDirectDrawLocal->cActiveSurface <=
|
|
peSurface->peDirectDrawLocal->cSurface,
|
|
"cActiveSurface is > than cSurface");
|
|
}
|
|
|
|
// We were successful, so unlock the surface:
|
|
|
|
hRet = peSurface->hGet();
|
|
DEC_EXCLUSIVE_REF_CNT(peSurface); // Unlock
|
|
}
|
|
else
|
|
{
|
|
// Delete the surface. Note that it may or may not
|
|
// yet have been completed:
|
|
|
|
bDdDeleteSurfaceObject(peSurface->hGet(), NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// This must be a complex surface (e.g. MipMap) that is getting called via the attach function.
|
|
// DDraw should call this again later to complete the surface.
|
|
|
|
hRet = peSurface->hGet();
|
|
DEC_EXCLUSIVE_REF_CNT(peSurface); // Unlock
|
|
}
|
|
}
|
|
}
|
|
else if (!(peDirectDrawGlobal->bSuspended))
|
|
{
|
|
// This is any video memory
|
|
|
|
peSurface = peDdOpenNewSurfaceObject(peDirectDrawLocal,
|
|
hSurface,
|
|
&SurfaceGlobal,
|
|
&SurfaceLocal,
|
|
&SurfaceMore);
|
|
if (peSurface != NULL)
|
|
{
|
|
if ((bComplete) &&
|
|
!(peSurface->fl & DD_SURFACE_FLAG_CREATE_COMPLETE))
|
|
{
|
|
// Only the kernel can create vidmem surface objects now, so
|
|
// if we're asked to 'complete' a surface that the kernel
|
|
// hasn't allocated, it's an error and no object should
|
|
// be completed. This weird code path is actually hit when
|
|
// user-mode DirectDraw tries to create a primary surface on
|
|
// a device whose driver doesn't support DirectDraw.
|
|
|
|
bDdDeleteSurfaceObject(peSurface->hGet(), NULL);
|
|
WARNING("DxDdCreateSurfaceObject: No DirectDraw driver");
|
|
}
|
|
else
|
|
{
|
|
if (bComplete)
|
|
{
|
|
ASSERTGDI(peSurface->hbmGdi == NULL,
|
|
"DxDdCreateSurfaceObject: Invalid cached bitmap");
|
|
|
|
// If this surface is in lost state, make it active.
|
|
|
|
if (peSurface->bLost)
|
|
{
|
|
peSurface->bLost = FALSE; // Surface can now be used
|
|
|
|
// Now this surface is ready to go, increment active surface ref. count.
|
|
|
|
peSurface->peDirectDrawLocal->cActiveSurface++;
|
|
|
|
ASSERTGDI(peSurface->peDirectDrawLocal->cActiveSurface <=
|
|
peSurface->peDirectDrawLocal->cSurface,
|
|
"cActiveSurface is > than cSurface");
|
|
}
|
|
}
|
|
|
|
// No need to call the CreateSurfaceEx here for this case
|
|
|
|
// We were successful, so unlock the surface:
|
|
|
|
hRet = peSurface->hGet();
|
|
DEC_EXCLUSIVE_REF_CNT(peSurface); // Unlock
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdCreateSurfaceObject: "
|
|
"Can't create because disabled\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdCreateSurfaceObjec: Bad handle or busy\n");
|
|
}
|
|
|
|
return(hRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DxDdDeleteSurfaceObject
|
|
*
|
|
* Deletes a kernel-mode representation of the surface.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
APIENTRY
|
|
DxDdDeleteSurfaceObject(
|
|
HANDLE hSurface
|
|
)
|
|
{
|
|
return(bDdDeleteSurfaceObject(hSurface, NULL));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ULONG DxDdResetVisrgn
|
|
*
|
|
* Registers a window for clipping.
|
|
*
|
|
* Remembers the current VisRgn state. Must be called before the VisRgn
|
|
* is downloaded and used.
|
|
*
|
|
* hwnd is currently not used.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
APIENTRY
|
|
DxDdResetVisrgn(
|
|
HANDLE hSurface,
|
|
HWND hwnd // 0 indicates no window clipping
|
|
) // -1 indicates any window can be written to
|
|
// otherwise indicates a particular window
|
|
{
|
|
BOOL bRet;
|
|
EDD_SURFACE* peSurface;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
|
|
bRet = FALSE;
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if (peSurface != NULL)
|
|
{
|
|
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
|
|
|
|
// We only care about the changes to the primary
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_PRIMARY)
|
|
{
|
|
peSurface->iVisRgnUniqueness = VISRGN_UNIQUENESS();
|
|
}
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ULONG DxDdReenableDirectDrawObject
|
|
*
|
|
* Resets the DirectDraw object after a mode change or after full-screen.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
APIENTRY
|
|
DxDdReenableDirectDrawObject(
|
|
HANDLE hDirectDrawLocal,
|
|
BOOL* pubNewMode
|
|
)
|
|
{
|
|
BOOL b;
|
|
HDC hdc;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
BOOL bModeChanged;
|
|
|
|
b = FALSE;
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDrawLocal);
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
// Get a DC on this HDEV so we can determine if the app has
|
|
// access to it. A NULL vis-region will be returned whenever
|
|
// something like a desktop has switched.
|
|
|
|
hdc = DxEngGetDesktopDC(DCTYPE_DIRECT, FALSE, FALSE);
|
|
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
{
|
|
EDD_SHAREDEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (DxEngGetDCState(hdc,DCSTATE_VISRGNCOMPLEX) != NULLREGION)
|
|
{
|
|
// DirectDraw can't be re-enabled while full-screen, or
|
|
// while USER has told us to disable DirectDraw, or when
|
|
// the colour depth is less than 8bpp:
|
|
|
|
if (!(po.bDisabled()) &&
|
|
!(po.bDeleted()) &&
|
|
(po.cDirectDrawDisableLocks() == 0) &&
|
|
(po.iDitherFormat() >= BMF_8BPP) &&
|
|
(peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_DRIVER_ENABLED))
|
|
{
|
|
bModeChanged
|
|
= (peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_MODE_CHANGED) != 0;
|
|
|
|
CheckAgpHeaps(peDirectDrawGlobal);
|
|
|
|
MapAllAgpHeaps(peDirectDrawLocal);
|
|
|
|
b = TRUE;
|
|
|
|
peDirectDrawGlobal->bSuspended = FALSE;
|
|
|
|
peDirectDrawGlobal->fl &= ~DD_GLOBAL_FLAG_MODE_CHANGED;
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteStructure(pubNewMode, bModeChanged, BOOL);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hdc)
|
|
{
|
|
DxEngDeleteDC(hdc, FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdReenableDirectDrawObject: Bad handle or busy\n");
|
|
}
|
|
|
|
return(b);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HBITMAP hbmDdCreateAndLockGdiSurface
|
|
*
|
|
* Creates a GDI surface derived from a DirectDraw surface. This routine
|
|
* may call the driver's DdLock function if it hasn't hooked (or fails)
|
|
* the DrvDeriveSurface call which gets the driver to wrap a GDI surface
|
|
* around a DirectDraw surface.
|
|
*
|
|
* Note that for the primary (GDI) surface, we can't simply return a handle
|
|
* back to the surface stashed in the PDEV. There are a couple of reasons
|
|
* for this:
|
|
*
|
|
* o The surface contains the palette, and at 8bpp the palette for
|
|
* a DirectDraw GetDC surface must have the DIB-Section flag set
|
|
* for proper colour matching. But the primary device surface can
|
|
* not have its palette marked as a DIB-Section.
|
|
*
|
|
* o GreSelectBitmap doesn't allow one surface to be selected into more
|
|
* than one DC.
|
|
*
|
|
* 22-Feb-1998 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBITMAP
|
|
hbmDdCreateAndLockGdiSurface(
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
EDD_SURFACE* peSurface,
|
|
PALETTEENTRY* puColorTable // Points to user-mode table
|
|
)
|
|
{
|
|
VOID* pvScan0;
|
|
VOID* pvBits;
|
|
LONG cjBits;
|
|
HBITMAP hbm;
|
|
ULONG iMode;
|
|
ULONG cColors;
|
|
ULONG i;
|
|
ULONG iFormat = 0;
|
|
|
|
// No color table is used for surfaces greater than 8bpp.
|
|
|
|
cColors = 0;
|
|
if (peSurface->ddpfSurface.dwRGBBitCount <= 8)
|
|
{
|
|
cColors = 1 << peSurface->ddpfSurface.dwRGBBitCount;
|
|
|
|
// Verify that the color table is safe to look at:
|
|
|
|
if (puColorTable != NULL)
|
|
{
|
|
__try
|
|
{
|
|
ProbeForRead(puColorTable, cColors * sizeof(PALETTEENTRY), 1);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("hbmDdCreateAndLockGdiSurface: Bad color table pointer");
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
// The bitmap's color table can be shared with the primary surface only
|
|
// if both are 8bpp:
|
|
|
|
if (puColorTable == NULL)
|
|
{
|
|
if ((peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount != 8) ||
|
|
(peSurface->ddpfSurface.dwRGBBitCount != 8))
|
|
{
|
|
WARNING("hbmDdCreateAndLockGdiSurface: Can't create shared palettes");
|
|
return(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
if (peSurface->hbmGdi != NULL)
|
|
{
|
|
// Ah ha, we already have a cached GDI surface. See if we need
|
|
// to call 'Lock', and then get out:
|
|
|
|
SURFOBJ* pso;
|
|
|
|
if ((pso = EngLockSurface((HSURF)(peSurface->hbmGdi))) != NULL)
|
|
{
|
|
if (peSurface->fl & DD_SURFACE_FLAG_BITMAP_NEEDS_LOCKING)
|
|
{
|
|
pvScan0 =
|
|
pDdLockSurfaceOrBuffer(peSurface, FALSE, NULL, DDLOCK_WAIT, NULL);
|
|
|
|
ASSERTGDI(pvScan0 != NULL,
|
|
"Driver failed lock call when it succeeded it before. Tsk, tsk");
|
|
|
|
// The driver’s allowed to move the surface around between locks, so
|
|
// update the bitmap address:
|
|
if ((pvScan0 != pso->pvScan0) &&
|
|
(pvScan0 != NULL))
|
|
{
|
|
pso->pvScan0 = pvScan0;
|
|
pso->pvBits = pvScan0;
|
|
}
|
|
}
|
|
|
|
// If it's 8bpp or less, we have to update the color table.
|
|
|
|
if (peSurface->ddpfSurface.dwRGBBitCount <= 8)
|
|
{
|
|
// Update the color table.
|
|
|
|
// Note that the scumy application might have delete the cached
|
|
// bitmap, so we have to check for bValid() here. (It's been a
|
|
// bad app, so we just protect against crashing, and don't bother
|
|
// to re-create a good bitmap for him.)
|
|
|
|
DxEngUploadPaletteEntryToSurface(po.hdev(),pso,puColorTable,cColors);
|
|
}
|
|
|
|
EngUnlockSurface(pso);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Okay, we have to create a GDI surface on the spot.
|
|
//
|
|
// First, The DirectDraw surface must be marked as RGB (even at 8bpp).
|
|
// GDI doesn't (yet) support drawing to YUV surfaces or the like. It
|
|
// also doesn't support 2bpp surfaces.
|
|
|
|
if ((peSurface->ddpfSurface.dwFlags & DDPF_RGB) &&
|
|
(peSurface->ddpfSurface.dwRGBBitCount != 2))
|
|
{
|
|
// We have to have the devlock since we'll be grunging around in
|
|
// the PDEV:
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
switch (peSurface->ddpfSurface.dwRGBBitCount)
|
|
{
|
|
case 1:
|
|
iFormat = BMF_1BPP; break;
|
|
case 4:
|
|
iFormat = BMF_4BPP; break;
|
|
case 8:
|
|
iFormat = BMF_8BPP; break;
|
|
case 16:
|
|
iFormat = BMF_16BPP; break;
|
|
case 24:
|
|
iFormat = BMF_24BPP; break;
|
|
case 32:
|
|
iFormat = BMF_32BPP; break;
|
|
default:
|
|
RIP("hbmDdCreateAndLockGdiSurface: Illegal dwRGBBitCount\n");
|
|
}
|
|
|
|
iMode = (iFormat <= BMF_8BPP) ? PAL_INDEXED : PAL_BITFIELDS;
|
|
|
|
HPALETTE hpal = EngCreatePalette(iMode,
|
|
cColors,
|
|
(ULONG*) puColorTable,
|
|
peSurface->ddpfSurface.dwRBitMask,
|
|
peSurface->ddpfSurface.dwGBitMask,
|
|
peSurface->ddpfSurface.dwBBitMask);
|
|
|
|
if (hpal)
|
|
{
|
|
if ((cColors == 256) && (puColorTable == NULL))
|
|
{
|
|
ASSERTGDI(po.bIsPalManaged(), "Expected palettized display");
|
|
|
|
// Make this palette share the same colour table as the
|
|
// screen, so that we always get identity blts:
|
|
|
|
DxEngSyncPaletteTableWithDevice(hpal,po.hdev());
|
|
}
|
|
|
|
hbm = 0;
|
|
|
|
// First, try getting the driver to create the surface, assuming
|
|
// it's a video memory surface.
|
|
|
|
if (!(peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
PPFNVALID(po, DeriveSurface))
|
|
{
|
|
hbm = PPFNDRV(po, DeriveSurface)(peDirectDrawGlobal,
|
|
peSurface);
|
|
if (hbm)
|
|
{
|
|
SURFOBJ* pso = EngLockSurface((HSURF)hbm);
|
|
if (pso)
|
|
{
|
|
// Mark surface as DirectDraw surface.
|
|
|
|
DxEngMarkSurfaceAsDirectDraw(pso,peSurface->hGet());
|
|
|
|
// Select the created palette to surface palette.
|
|
|
|
DxEngSelectPaletteToSurface(pso,hpal);
|
|
|
|
EngUnlockSurface(pso);
|
|
}
|
|
else
|
|
{
|
|
EngDeleteSurface((HSURF)hbm);
|
|
hbm = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Next, try getting GDI to create the surface:
|
|
|
|
if (hbm == 0)
|
|
{
|
|
// Note that this lock will fail when the PDEV isn't active,
|
|
// meaning that GetDC will return 0 when full-screen.
|
|
// GDI won't barf on any calls where the HDC is passed in as
|
|
// 0, so this is okay.
|
|
|
|
pvScan0 = pDdLockSurfaceOrBuffer(peSurface, FALSE,
|
|
NULL, DDLOCK_WAIT, NULL);
|
|
if (pvScan0 != NULL)
|
|
{
|
|
FLONG fl;
|
|
SIZEL sizl;
|
|
|
|
sizl.cx = peSurface->wWidth;
|
|
sizl.cy = peSurface->wHeight;
|
|
fl = BMF_TOPDOWN;
|
|
pvBits = pvScan0;
|
|
cjBits = (LONG) peSurface->wHeight * peSurface->lPitch;
|
|
if (cjBits < 0)
|
|
{
|
|
fl = 0;
|
|
cjBits = -cjBits;
|
|
pvBits = (BYTE*) pvScan0 - cjBits - peSurface->lPitch;
|
|
}
|
|
|
|
hbm = EngCreateBitmap(sizl,
|
|
0,
|
|
iFormat,
|
|
fl,
|
|
pvBits);
|
|
|
|
// Mark the palette as a DIB-Section so that any color-
|
|
// matching on the DC actually uses the entire device
|
|
// palette, NOT what the logical palette selected into
|
|
// the DC.
|
|
|
|
DxEngSetPaletteState(hpal,PALSTATE_DIBSECTION,(ULONG_PTR)TRUE);
|
|
|
|
if (hbm)
|
|
{
|
|
SURFOBJ* pso = EngLockSurface((HSURF) hbm);
|
|
if (pso)
|
|
{
|
|
peSurface->fl |= DD_SURFACE_FLAG_BITMAP_NEEDS_LOCKING;
|
|
|
|
// Select the created palette to surface palette.
|
|
|
|
DxEngSelectPaletteToSurface(pso,hpal);
|
|
|
|
// Mark surface as DirectDraw surface.
|
|
|
|
DxEngMarkSurfaceAsDirectDraw(pso,peSurface->hGet());
|
|
|
|
// Override some fields which we couldn't specify in
|
|
// the 'EngCreateBitmap' call. The following 3 are due to
|
|
// the fact that we couldn't pass in a stride:
|
|
|
|
pso->lDelta = peSurface->lPitch;
|
|
pso->pvScan0 = pvScan0;
|
|
pso->cjBits = cjBits;
|
|
pso->fjBitmap |= BMF_DONTCACHE;
|
|
|
|
if (!(peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
|
|
{
|
|
pso->fjBitmap |= BMF_NOTSYSMEM;
|
|
}
|
|
|
|
EngUnlockSurface(pso);
|
|
}
|
|
else
|
|
{
|
|
EngDeleteSurface((HSURF)hbm);
|
|
hbm = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bDdUnlockSurfaceOrBuffer(peSurface);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hbm)
|
|
{
|
|
// Success, we're done!
|
|
//
|
|
// Set handle owner to current process.
|
|
|
|
DxEngSetBitmapOwner(hbm, OBJECT_OWNER_CURRENT);
|
|
|
|
peSurface->hbmGdi = hbm;
|
|
|
|
// TODO: Palette needs to be owned by this process.
|
|
|
|
peSurface->hpalGdi = hpal;
|
|
}
|
|
else
|
|
{
|
|
EngDeletePalette(hpal);
|
|
}
|
|
}
|
|
}
|
|
else if (!(peSurface->ddpfSurface.dwFlags & DDPF_ZBUFFER))
|
|
{
|
|
WARNING("hbbDdCreateAndLockGdiSurface: Invalid surface or RGB type\n");
|
|
}
|
|
}
|
|
|
|
return(peSurface->hbmGdi);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDdUnlockGdiSurface
|
|
*
|
|
* Unlocks the view required for the GDI bitmap if necessary (that is, if
|
|
* the driver didn't hook DrvDeriveSurface, or failed it).
|
|
*
|
|
* 22-Feb-1998 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID FASTCALL
|
|
vDdUnlockGdiSurface(
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
if (peSurface->fl & DD_SURFACE_FLAG_BITMAP_NEEDS_LOCKING)
|
|
{
|
|
bDdUnlockSurfaceOrBuffer(peSurface);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HDC DxDdGetDC
|
|
*
|
|
* Creates a DC that can be used to draw to an off-screen DirectDraw
|
|
* surface.
|
|
*
|
|
* Essentially, this works as follows:
|
|
*
|
|
* o Do a DirectDraw Lock on the specified surface;
|
|
* o CreateDIBSection of the appropriate format pointing to that surface;
|
|
* o CreateCompatibleDC to get a DC;
|
|
* o Select the DIBSection into the compatible DC
|
|
*
|
|
* At 8bpp, however, the DIBSection is not a 'normal' DIBSection. It's
|
|
* created with no palette so that it it behaves as a device-dependent
|
|
* bitmap: the color table is the same as the display.
|
|
*
|
|
* GDI will do all drawing to the surface using the user-mode mapping of
|
|
* the frame buffer. Since all drawing to the created DC will occur in the
|
|
* context of the application's process, this is not a problem. We do have
|
|
* to watch out that we don't blow away the section view while a thread is
|
|
* in kernel-mode GDI drawing; however, this problem would have to be solved
|
|
* even if using a kernel-mode mapping of the section because we don't want
|
|
* any drawing intended for an old PDEV to get through to a new PDEV after
|
|
* a mode change has occured, for example.
|
|
*
|
|
* A tricky part of GetDC is how to blow away the surface lock while a thread
|
|
* could be in kernel-mode GDI about to draw using the surface pointer. We
|
|
* solve that problem by changing the DC's VisRgn to be an empty region when
|
|
* trying to blow away all the surface locks.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HDC
|
|
APIENTRY
|
|
DxDdGetDC(
|
|
HANDLE hSurface,
|
|
PALETTEENTRY* puColorTable
|
|
)
|
|
{
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_SURFACE* peSurface;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
HDC hdc;
|
|
HBITMAP hbm;
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if (peSurface != NULL)
|
|
{
|
|
// DirectDraw doesn't let an application have more than one active
|
|
// GetDC DC to a surface at a time:
|
|
|
|
if (peSurface->hdc != 0)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
|
|
|
|
// Grab the devlock because hbmDdCreateAndLockGdiSurface grunges
|
|
// around in the global data.
|
|
|
|
EDD_SHAREDEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (!peSurface->bLost)
|
|
{
|
|
// Note that 'hbmDdCreateAndLockGdiSurface' keeps a bitmap cache,
|
|
// so this should usually be pretty quick:
|
|
|
|
hbm = hbmDdCreateAndLockGdiSurface(peDirectDrawGlobal,
|
|
peSurface,
|
|
puColorTable);
|
|
if (hbm != NULL)
|
|
{
|
|
// First, try to get a DC from the cache:
|
|
|
|
hdc = (HDC) peDirectDrawGlobal->hdcCache;
|
|
if (hdc != NULL)
|
|
{
|
|
// This will succeed only if we atomically managed to
|
|
// grab the cached DC (there may be other threads
|
|
// calling 'bDdReleaseDC' at exactly the same time).
|
|
|
|
if (InterlockedCompareExchangePointer(
|
|
&peDirectDrawGlobal->hdcCache,
|
|
NULL,
|
|
(VOID*) hdc) == hdc)
|
|
{
|
|
|
|
// Set the DC's ownership to the current process so
|
|
// that it will get cleaned up if the process terminates
|
|
// unexpectedly.
|
|
|
|
BOOL bSet = DxEngSetDCOwner(hdc, OBJECT_OWNER_CURRENT);
|
|
|
|
ASSERTGDI(bSet, "DxDdGetDC: Cached DC was invalid");
|
|
}
|
|
else
|
|
{
|
|
hdc = NULL;
|
|
}
|
|
}
|
|
|
|
if (hdc == NULL)
|
|
{
|
|
// Now, create the DC for the actual drawing, owned by the
|
|
// current process.
|
|
|
|
hdc = DxEngCreateMemoryDC(peDirectDrawGlobal->hdev);
|
|
}
|
|
|
|
if (hdc)
|
|
{
|
|
// Finally, select our surface into the DC. It
|
|
// doesn't matter if this fails for some bizarre
|
|
// reason; the default bitmap will be stuck in there
|
|
// instead.
|
|
|
|
HBITMAP hbmOld = DxEngSelectBitmap(hdc, hbm);
|
|
|
|
ASSERTGDI(hbmOld, "DxDdGetDC: Invalid selection");
|
|
|
|
peSurface->hdc = hdc;
|
|
|
|
// I'm paranoid, so let's verify that we've set things
|
|
// up correctly:
|
|
|
|
#if 0 // TODO: DBG - DC
|
|
{
|
|
DCOBJ dco(hdc);
|
|
ASSERTGDI(dco.bValid(),
|
|
"DxDdGetDC: Should have a valid DC");
|
|
ASSERTGDI(!dco.bFullScreen(),
|
|
"DxDdGetDC: DC shouldn't be disabled");
|
|
ASSERTGDI(dco.bSynchronizeAccess(),
|
|
"DxDdGetDC: Should mark devlock needed");
|
|
ASSERTGDI(dco.pSurfaceEff()->bDirectDraw(),
|
|
"DxDdGetDC: Should mark as DDraw surface");
|
|
ASSERTGDI(dco.dctp() == DCTYPE_MEMORY,
|
|
"DxDdGetDC: Should be memory DC");
|
|
}
|
|
#endif
|
|
|
|
// For debugging purposes:
|
|
|
|
ghdcGetDC = hdc;
|
|
|
|
return(hdc);
|
|
}
|
|
|
|
vDdUnlockGdiSurface(peSurface);
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetDC: hbmDdCreateAndLockGdiSurface failed\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetDC: Couldn't lock the surface\n");
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdReleaseDC
|
|
*
|
|
* Deletes a DC created via DdGetDC.
|
|
*
|
|
* The devlock should not be held when entering this function.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdReleaseDC(
|
|
EDD_SURFACE* peSurface,
|
|
BOOL bForce // True when cleaning up surface
|
|
)
|
|
{
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
BOOL bRet = FALSE;
|
|
BOOL bClean;
|
|
HDC hdc;
|
|
|
|
hdc = peSurface->hdc;
|
|
if (hdc)
|
|
{
|
|
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
|
|
|
|
#if 0 // Temporary disable DC cache for bug 176728
|
|
|
|
// See if there's already a DC in the one-deep cache:
|
|
|
|
if (!peDirectDrawGlobal->hdcCache)
|
|
{
|
|
// Okay, it looks like we can cache this DC. Clean it up first,
|
|
// which among other things unselects the current DirectDraw
|
|
// GDI surface. Then set the owner to 'none' so that it
|
|
// doesn't get deleted when the current process terminates and
|
|
// no one can touch it until we pick up from cache.
|
|
|
|
if (DxEngCleanDC(hdc) &&
|
|
DxEngSetDCOwner(hdc, OBJECT_OWNER_NONE))
|
|
{
|
|
// Atomically try to stick the DC into the cache. Note that
|
|
// it's okay if this fails and we fall into 'bDeleteDCInternal',
|
|
//
|
|
// Note that we use 'InterlockedCompareExchangePointer' so that
|
|
// we can avoid acquiring the devlock in most cases through
|
|
// bDdReleaseDC. So if someone changes this code to acquire
|
|
// the devlock, there's really no pointer in doing this via
|
|
// an Interlocked method.
|
|
|
|
if (InterlockedCompareExchangePointer(
|
|
&peDirectDrawGlobal->hdcCache,
|
|
(VOID*) hdc,
|
|
NULL) == NULL)
|
|
{
|
|
// Success, we cached the DC!
|
|
|
|
hdc = NULL;
|
|
}
|
|
else
|
|
{
|
|
// Need to be belonging to current process in order to delete.
|
|
// since we already changed the owner to 'none' above.
|
|
|
|
DxEngSetDCOwner(hdc, OBJECT_OWNER_CURRENT);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("bDdReleaseDC: Not caching DC, app may have deleted it");
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
if (hdc)
|
|
{
|
|
// There's already a DC in the cache. So delete this one.
|
|
//
|
|
// Note that the application could have called DeleteObject(hdc)
|
|
// or SelectObject(hdc, hSomeOtherBitmap) with the DC we gave
|
|
// them. That's okay, though: nothing will crash, just some of
|
|
// the below operations may fail because they've already been
|
|
// done:
|
|
|
|
if (!DxEngDeleteDC(hdc, TRUE))
|
|
{
|
|
WARNING("bDdReleaseDC: Couldn't delete DC\n");
|
|
}
|
|
}
|
|
|
|
// Call the driver's DdUnlock if necessary:
|
|
|
|
vDdUnlockGdiSurface(peSurface);
|
|
|
|
peSurface->hdc = NULL;
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DxDdReleaseDC
|
|
*
|
|
* User-mode callable routine to delete a DC created via DdGetDC.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
APIENTRY
|
|
DxDdReleaseDC(
|
|
HANDLE hSurface
|
|
)
|
|
{
|
|
BOOL bRet;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_SURFACE* peSurface;
|
|
|
|
bRet = FALSE;
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if (peSurface != NULL)
|
|
{
|
|
bRet = bDdReleaseDC(peSurface, FALSE);
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DxDdAttachSurface
|
|
*
|
|
* Transmogrified from Win95's ddsatch.c AddAttachedSurface. Don't blame
|
|
* me for this wonderful attach system; the attach links are used by drivers
|
|
* and so we have to be compatible with Win95.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
APIENTRY
|
|
DxDdAttachSurface(
|
|
HANDLE hSurfaceFrom, // hSurfaceFrom will point 'to' hSurfaceTo
|
|
// (think of this as the main surface)
|
|
HANDLE hSurfaceTo // hSurfaceTo will point 'from' hSurfaceFrom
|
|
) // (think of this as the secondary surface)
|
|
{
|
|
EDD_LOCK_SURFACE eLockSurfaceFrom;
|
|
EDD_LOCK_SURFACE eLockSurfaceTo;
|
|
EDD_SURFACE* peSurfaceFrom;
|
|
EDD_SURFACE* peSurfaceTo;
|
|
DD_ATTACHLIST* pAttachFrom;
|
|
DD_ATTACHLIST* pAttachTo;
|
|
DD_ATTACHLIST* pAttach;
|
|
DD_ATTACHLIST* pAttachTemp;
|
|
BOOL bAttach;
|
|
BOOL bRet;
|
|
|
|
bRet = FALSE; // Assume failure
|
|
|
|
peSurfaceFrom = eLockSurfaceFrom.peLock(hSurfaceFrom);
|
|
peSurfaceTo = eLockSurfaceTo.peLock(hSurfaceTo);
|
|
if ((peSurfaceFrom != NULL) && (peSurfaceTo != NULL))
|
|
{
|
|
if (peSurfaceFrom->peDirectDrawLocal == peSurfaceTo->peDirectDrawLocal)
|
|
{
|
|
// Use the devlock to synchronize additions and deletions to
|
|
// the attach list:
|
|
|
|
EDD_DEVLOCK eDevLock(peSurfaceFrom->peDirectDrawGlobal);
|
|
|
|
// First, see if the surface is already attached or in the
|
|
// chain. If so, don't add it again
|
|
|
|
bAttach = TRUE;
|
|
for (pAttach = peSurfaceFrom->lpAttachListFrom;
|
|
pAttach != NULL;
|
|
pAttach = pAttach->lpAttached->lpAttachListFrom)
|
|
{
|
|
for (pAttachTemp = pAttach;
|
|
pAttachTemp != NULL;
|
|
pAttachTemp = pAttachTemp->lpLink)
|
|
{
|
|
if (pedFromLp(pAttachTemp->lpAttached) == peSurfaceTo)
|
|
bAttach = FALSE;
|
|
}
|
|
}
|
|
for (pAttach = peSurfaceTo->lpAttachList;
|
|
pAttach != NULL;
|
|
pAttach = pAttach->lpAttached->lpAttachList)
|
|
{
|
|
for (pAttachTemp = pAttach;
|
|
pAttachTemp != NULL;
|
|
pAttachTemp = pAttachTemp->lpLink)
|
|
{
|
|
if (pedFromLp(pAttachTemp->lpAttached) == peSurfaceTo)
|
|
bAttach = FALSE;
|
|
}
|
|
}
|
|
|
|
if (bAttach)
|
|
{
|
|
pAttachFrom = (DD_ATTACHLIST*) PALLOCMEM(sizeof(*pAttachFrom),
|
|
'addG');
|
|
if (pAttachFrom != NULL)
|
|
{
|
|
pAttachTo = (DD_ATTACHLIST*) PALLOCMEM(sizeof(*pAttachTo),
|
|
'addG');
|
|
if (pAttachTo != NULL)
|
|
{
|
|
pAttachFrom->lpAttached = peSurfaceTo;
|
|
pAttachFrom->lpLink = peSurfaceFrom->lpAttachList;
|
|
peSurfaceFrom->lpAttachList = pAttachFrom;
|
|
|
|
pAttachTo->lpAttached = peSurfaceFrom;
|
|
pAttachTo->lpLink = peSurfaceTo->lpAttachListFrom;
|
|
peSurfaceTo->lpAttachListFrom = pAttachTo;
|
|
|
|
vDdUpdateMipMapCount(peSurfaceTo);
|
|
bRet = TRUE;
|
|
}
|
|
|
|
if (!bRet)
|
|
{
|
|
VFREEMEM(pAttachFrom);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdAttachSurface: Surfaces already attached");
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdAttachSurface: Surfaces not for same device");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdAttachSurface: Invalid surface specified");
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DxDdUnattachSurface
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
APIENTRY
|
|
DxDdUnattachSurface(
|
|
HANDLE hSurface,
|
|
HANDLE hSurfaceAttached
|
|
)
|
|
{
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_LOCK_SURFACE eLockSurfaceAttached;
|
|
EDD_SURFACE* peSurface;
|
|
EDD_SURFACE* peSurfaceAttached;
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
peSurfaceAttached = eLockSurfaceAttached.peLock(hSurfaceAttached);
|
|
if ((peSurface != NULL) && (peSurfaceAttached != NULL))
|
|
{
|
|
// Use the devlock to synchronize additions and deletions to
|
|
// the attach list:
|
|
|
|
EDD_DEVLOCK eDevLock(peSurface->peDirectDrawGlobal);
|
|
|
|
if (bDdRemoveAttachedSurface(peSurface, peSurfaceAttached))
|
|
{
|
|
vDdUpdateMipMapCount(peSurface);
|
|
vDdUpdateMipMapCount(peSurfaceAttached);
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdUnattachSurface: Surface not attached");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdUnattachSurface: Invalid surface specified");
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD dwDdBltViaGdi
|
|
*
|
|
* This routine will attempt to do a non-stretching, non-system-memory to
|
|
* non-system-memory blt, or system-memory to non-system-memory blt via the
|
|
* driver's CopyBits routine. The motivation for this is two-fold:
|
|
*
|
|
* 1. If the system-memory to video-memory blt has to be emulated, we can
|
|
* do a better emulation job here from the kernel than the HEL can from
|
|
* user-mode, where it has to call Lock/Unlock. We get a couple of
|
|
* benefits:
|
|
*
|
|
* o We can do the blt in one kernel-mode transition, instead
|
|
* of the two previously needed for the lock and unlock;
|
|
*
|
|
* o Because we don't have to hold from user-mode a DirectDraw Lock
|
|
* on the video memory, we don't run the risk of having to
|
|
* redraw if the clipping changes asynchronously;
|
|
*
|
|
* o We can handle blts underneath emulated sprites without having
|
|
* to tear down the sprites, by virtue of going through
|
|
* SpCopyBits. This means, among other things, that the
|
|
* cursor won't flash.
|
|
*
|
|
* 2. For non-system-memory to video-memory blts, we can handle blts to the
|
|
* underneath emulated sprites without having to tear down the sprites,
|
|
* by virtue of going through SpCopyBits.
|
|
*
|
|
* Returns DDHAL_DRIVER_HANDLED if GDI handled the blt; DDHAL_DRIVER_NOTHANDLED
|
|
* if the blt should be handled by the driver's HAL.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
dwDdBltViaGdi(
|
|
EDD_SURFACE* peSurfaceDest,
|
|
EDD_SURFACE* peSurfaceSrc,
|
|
DD_BLTDATA* pBltData
|
|
)
|
|
{
|
|
DWORD dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
HBITMAP hbmDest;
|
|
HBITMAP hbmSrc;
|
|
BOOL bGdiCandidate;
|
|
|
|
// If the sources are compatible, and the destination is video-memory,
|
|
// we may want to call the driver through GDI. We do this primarily
|
|
// to handle blts that occur underneath emulated sprites, so that we
|
|
// don't have to tear down the sprite.
|
|
|
|
if ((peSurfaceSrc != NULL) &&
|
|
(peSurfaceDest->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
|
|
{
|
|
peDirectDrawGlobal = peSurfaceDest->peDirectDrawGlobal;
|
|
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
// We're acting as the HEL for system-memory to video-memory
|
|
// blts, and so those cases always have to go through GDI.
|
|
//
|
|
// Otherwise, we go through CopyBits only if:
|
|
//
|
|
// o The destination is the primary GDI surface;
|
|
// o Sprites are visible;
|
|
// o The source surface can be accelerated;
|
|
// o There isn't a stretch.
|
|
|
|
bGdiCandidate = FALSE;
|
|
|
|
// If we're emulating system-memory to video-memory blts, we have
|
|
// to take all system-memory to video-memory blts here (we never
|
|
// said we'd do stretches or anything weird, but we don't want to
|
|
// pass any system-memory to video-memory calls at all to the driver,
|
|
// since it may fall-over when it gets a surface type it doesn't
|
|
// expect).
|
|
|
|
if ((peSurfaceSrc->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
(peDirectDrawGlobal->flDriver & DD_DRIVER_FLAG_EMULATE_SYSTEM_TO_VIDEO) &&
|
|
(peSurfaceDest->fl & DD_SURFACE_FLAG_PRIMARY))
|
|
{
|
|
bGdiCandidate = TRUE;
|
|
|
|
// As a robustness thing, don't let *any* system-memory to video-
|
|
// memory blts down to the driver if it didn't ask for it.
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
}
|
|
|
|
// If the destination is the primary GDI surface and any sprites
|
|
// are visible, we also vector through GDI in order to be able to
|
|
// handle blts underneath sprites without flashing.
|
|
|
|
else if ((peSurfaceDest->fl & DD_SURFACE_FLAG_PRIMARY) &&
|
|
(DxEngSpSpritesVisible(peDirectDrawGlobal->hdev)) &&
|
|
((PPFNVALID(po, DeriveSurface)) ||
|
|
(peSurfaceSrc->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)))
|
|
{
|
|
bGdiCandidate = TRUE;
|
|
}
|
|
|
|
// Add cases where CopyBits can not handle the blit
|
|
//
|
|
// 1. color keying
|
|
// 2. FX blit(mirror)
|
|
// 3. Blit has color space conversion, e.g. YUV to RGB
|
|
|
|
if (bGdiCandidate)
|
|
{
|
|
bGdiCandidate=FALSE;
|
|
|
|
if (!(pBltData->dwFlags & (DDBLT_KEYSRCOVERRIDE |
|
|
DDBLT_KEYDESTOVERRIDE |
|
|
DDBLT_KEYSRC |
|
|
DDBLT_KEYDEST |
|
|
DDBLT_DDFX)) &&
|
|
(peSurfaceDest->ddpfSurface.dwRGBBitCount
|
|
== peSurfaceSrc->ddpfSurface.dwRGBBitCount))
|
|
{
|
|
DWORD dwDestFlags = peSurfaceDest->ddpfSurface.dwFlags;
|
|
DWORD dwSrcFlags = peSurfaceSrc->ddpfSurface.dwFlags;
|
|
|
|
dwDestFlags &= (DDPF_RGB|DDPF_PALETTEINDEXED8);
|
|
dwSrcFlags &= (DDPF_RGB|DDPF_PALETTEINDEXED8);
|
|
|
|
if ((dwDestFlags != 0) && (dwDestFlags==dwSrcFlags))
|
|
{
|
|
if (!(dwSrcFlags & DDPF_PALETTEINDEXED8))
|
|
{
|
|
if ((peSurfaceDest->ddpfSurface.dwRBitMask
|
|
== peSurfaceSrc->ddpfSurface.dwRBitMask) &&
|
|
(peSurfaceDest->ddpfSurface.dwGBitMask
|
|
== peSurfaceSrc->ddpfSurface.dwGBitMask) &&
|
|
(peSurfaceDest->ddpfSurface.dwBBitMask
|
|
== peSurfaceSrc->ddpfSurface.dwBBitMask))
|
|
{
|
|
bGdiCandidate=TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bGdiCandidate=TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((bGdiCandidate) &&
|
|
((pBltData->rDest.right - pBltData->rDest.left)
|
|
== (pBltData->rSrc.right - pBltData->rSrc.left)) &&
|
|
((pBltData->rDest.bottom - pBltData->rDest.top)
|
|
== (pBltData->rSrc.bottom - pBltData->rSrc.top)))
|
|
{
|
|
// At this point, GDI is definitely going to handle the
|
|
// blt (or die trying):
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
pBltData->ddRVal = DD_OK;
|
|
|
|
// If a hardware flip is pending on this surface, then wait for
|
|
// the flip to finish before continuing:
|
|
|
|
if (peSurfaceDest->fl & DD_SURFACE_FLAG_FLIP_PENDING)
|
|
{
|
|
ASSERTGDI(
|
|
(peDirectDrawGlobal->SurfaceCallBacks.dwFlags &
|
|
DDHAL_SURFCB32_GETFLIPSTATUS) &&
|
|
peDirectDrawGlobal->SurfaceCallBacks.GetFlipStatus,
|
|
"Flip pending but GetFlipStatus unsupported by driver?");
|
|
|
|
DD_GETFLIPSTATUSDATA GetFlipStatusData;
|
|
DWORD dwFlipRet;
|
|
|
|
GetFlipStatusData.lpDD = peDirectDrawGlobal;
|
|
GetFlipStatusData.lpDDSurface = peSurfaceDest;
|
|
GetFlipStatusData.dwFlags = DDGFS_ISFLIPDONE;
|
|
GetFlipStatusData.GetFlipStatus = NULL;
|
|
GetFlipStatusData.ddRVal = DDERR_GENERIC;
|
|
|
|
do
|
|
{
|
|
dwFlipRet = peDirectDrawGlobal->
|
|
SurfaceCallBacks.GetFlipStatus(&GetFlipStatusData);
|
|
|
|
} while (
|
|
(dwFlipRet == DDHAL_DRIVER_HANDLED) &&
|
|
(GetFlipStatusData.ddRVal == DDERR_WASSTILLDRAWING));
|
|
|
|
peSurfaceDest->fl &= ~DD_SURFACE_FLAG_FLIP_PENDING;
|
|
}
|
|
|
|
// If the surfaces are primary (GDI) surfaces, just use
|
|
// the GDI surface we have stashed in the PDEV:
|
|
|
|
hbmDest = (HBITMAP) po.hsurf();
|
|
hbmSrc = (HBITMAP) po.hsurf();
|
|
|
|
if (!(peSurfaceDest->fl & DD_SURFACE_FLAG_PRIMARY))
|
|
{
|
|
hbmDest = hbmDdCreateAndLockGdiSurface(peDirectDrawGlobal,
|
|
peSurfaceDest,
|
|
NULL);
|
|
}
|
|
|
|
if (!(peSurfaceSrc->fl & DD_SURFACE_FLAG_PRIMARY))
|
|
{
|
|
hbmSrc = hbmDdCreateAndLockGdiSurface(peDirectDrawGlobal,
|
|
peSurfaceSrc,
|
|
NULL);
|
|
}
|
|
|
|
SURFOBJ *psoDest = EngLockSurface((HSURF) hbmDest);
|
|
SURFOBJ *psoSrc = EngLockSurface((HSURF) hbmSrc);
|
|
|
|
if (psoDest && psoSrc)
|
|
{
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
// A malicious app may have given us stretch values on
|
|
// system-memory to video-memory blts, so check:
|
|
|
|
if (((pBltData->rDest.right - pBltData->rDest.left)
|
|
== (pBltData->rSrc.right - pBltData->rSrc.left)) &&
|
|
((pBltData->rDest.bottom - pBltData->rDest.top)
|
|
== (pBltData->rSrc.bottom - pBltData->rSrc.top)))
|
|
{
|
|
(*PPFNGET(po, CopyBits, SURFOBJ_HOOK(psoDest)))
|
|
(psoDest,
|
|
psoSrc,
|
|
NULL,
|
|
NULL,
|
|
&pBltData->rDest,
|
|
(POINTL*) &pBltData->rSrc);
|
|
}
|
|
}
|
|
|
|
if (psoDest)
|
|
{
|
|
EngUnlockSurface(psoDest);
|
|
}
|
|
|
|
if (psoSrc)
|
|
{
|
|
EngUnlockSurface(psoSrc);
|
|
}
|
|
|
|
if (!(peSurfaceDest->fl & DD_SURFACE_FLAG_PRIMARY))
|
|
{
|
|
vDdUnlockGdiSurface(peSurfaceDest);
|
|
}
|
|
|
|
if (!(peSurfaceSrc->fl & DD_SURFACE_FLAG_PRIMARY))
|
|
{
|
|
vDdUnlockGdiSurface(peSurfaceSrc);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdBlt
|
|
*
|
|
* DirectDraw blt.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdBlt(
|
|
HANDLE hSurfaceDest,
|
|
HANDLE hSurfaceSrc,
|
|
PDD_BLTDATA puBltData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_BLTDATA BltData;
|
|
#ifdef DX_REDIRECTION
|
|
HWND hWnd;
|
|
#endif // DX_REDIRECTION
|
|
|
|
__try
|
|
{
|
|
ProbeForRead(puBltData, sizeof(DD_BLTDATA), sizeof(DWORD));
|
|
|
|
// To save some copying time, we copy only those fields which are
|
|
// supported for NT drivers:
|
|
|
|
BltData.rDest.left = puBltData->rDest.left;
|
|
BltData.rDest.top = puBltData->rDest.top;
|
|
BltData.rDest.right = puBltData->rDest.right;
|
|
BltData.rDest.bottom = puBltData->rDest.bottom;
|
|
BltData.rSrc.left = puBltData->rSrc.left;
|
|
BltData.rSrc.top = puBltData->rSrc.top;
|
|
BltData.rSrc.right = puBltData->rSrc.right;
|
|
BltData.rSrc.bottom = puBltData->rSrc.bottom;
|
|
|
|
BltData.dwFlags = puBltData->dwFlags;
|
|
BltData.bltFX.dwFillColor = puBltData->bltFX.dwFillColor;
|
|
BltData.bltFX.ddckSrcColorkey = puBltData->bltFX.ddckSrcColorkey;
|
|
BltData.bltFX.ddckDestColorkey= puBltData->bltFX.ddckDestColorkey;
|
|
BltData.bltFX.dwDDFX = puBltData->bltFX.dwDDFX;
|
|
|
|
#ifdef DX_REDIRECTION
|
|
// DD_BLTDATA.Blt member contains hWnd.
|
|
hWnd = (HWND)(puBltData->Blt);
|
|
#endif // DX_REDIRECTION
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
BltData.ddRVal = DDERR_GENERIC;
|
|
|
|
#ifdef DX_REDIRECTION
|
|
// if hWnd is given and redirection is enabled on the hWnd,
|
|
// we just fail this call here, and let ddraw runtime to uses
|
|
// emulation code, which eventually call GDI Blt functions.
|
|
|
|
if (hWnd)
|
|
{
|
|
if (DxEngGetRedirectionBitmap(hWnd))
|
|
{
|
|
return(dwRet);
|
|
}
|
|
}
|
|
#endif // DX_REDIRECTION
|
|
|
|
EDD_SURFACE* peSurfaceDest;
|
|
EDD_SURFACE* peSurfaceSrc;
|
|
DWORD dwFlags;
|
|
EDD_LOCK_SURFACE eLockSurfaceDest;
|
|
EDD_LOCK_SURFACE eLockSurfaceSrc;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
DWORD dwSrcCaps;
|
|
DWORD dwDestCaps;
|
|
DDNTCORECAPS* pCaps;
|
|
BOOL bUnTearDown;
|
|
|
|
peSurfaceDest = eLockSurfaceDest.peLock(hSurfaceDest);
|
|
BltData.lpDDDestSurface = peSurfaceDest;
|
|
|
|
if (peSurfaceDest != NULL)
|
|
{
|
|
peDirectDrawGlobal = peSurfaceDest->peDirectDrawGlobal;
|
|
|
|
// We support only a specific set of Blt calls down to the driver
|
|
// that we're willing to support and to test.
|
|
|
|
dwFlags = BltData.dwFlags;
|
|
if (((dwFlags & (DDBLT_ROTATIONANGLE)) == 0) &&
|
|
((dwFlags & (DDBLT_ROP
|
|
| DDBLT_COLORFILL
|
|
| DDBLT_DEPTHFILL)) != 0))
|
|
{
|
|
// I think ROPs are goofy, so we always tell the application
|
|
// that our hardware can only do SRCCOPY blts, but we should
|
|
// make sure the driver doesn't fall over if it gets something
|
|
// unexpected. And they can look at this even if DDBLT_DDFX
|
|
// isn't set:
|
|
|
|
BltData.bltFX.dwROP = 0xCC0000; // SRCCOPY in DirectDraw format
|
|
|
|
// No support for IsClipped for now -- we would have to
|
|
// validate and copy the prDestRects array:
|
|
|
|
BltData.IsClipped = FALSE;
|
|
|
|
if (dwFlags & DDBLT_DDFX)
|
|
{
|
|
// The only DDBLT_DDFX functionality we allow down to the
|
|
// driver is DDBLTFX_NOTEARING:
|
|
// DDBLTFX_MIRRORLEFTRIGHT
|
|
// DDBLTFX_MIRRORUPDOWN
|
|
|
|
if (BltData.bltFX.dwDDFX & ~(DDBLTFX_NOTEARING
|
|
|DDBLTFX_MIRRORLEFTRIGHT
|
|
|DDBLTFX_MIRRORUPDOWN)
|
|
)
|
|
{
|
|
WARNING("DxDdBlt: Invalid dwDDFX\n");
|
|
return(dwRet);
|
|
}
|
|
}
|
|
|
|
if (dwFlags & (DDBLT_COLORFILL | DDBLT_DEPTHFILL))
|
|
{
|
|
// Do simpler stuff 'cause we don't need to lock a source:
|
|
|
|
BltData.lpDDSrcSurface = NULL;
|
|
peSurfaceSrc = NULL;
|
|
|
|
if (peSurfaceDest->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
WARNING("DxDdBlt: Can't blt to system memory surface");
|
|
return(dwRet);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Lock the source surface:
|
|
|
|
peSurfaceSrc = eLockSurfaceSrc.peLock(hSurfaceSrc);
|
|
BltData.lpDDSrcSurface = peSurfaceSrc;
|
|
|
|
// Ensure that both surfaces belong to the same DirectDraw
|
|
// object, and check source rectangle:
|
|
|
|
if ((peSurfaceSrc == NULL) ||
|
|
(peSurfaceSrc->peDirectDrawLocal !=
|
|
peSurfaceDest->peDirectDrawLocal) ||
|
|
(BltData.rSrc.left < 0) ||
|
|
(BltData.rSrc.top < 0) ||
|
|
(BltData.rSrc.right > (LONG) peSurfaceSrc->wWidth) ||
|
|
(BltData.rSrc.bottom > (LONG) peSurfaceSrc->wHeight) ||
|
|
(BltData.rSrc.left >= BltData.rSrc.right) ||
|
|
(BltData.rSrc.top >= BltData.rSrc.bottom))
|
|
{
|
|
WARNING("DxDdBlt: Invalid source surface or source rectangle\n");
|
|
return(dwRet);
|
|
}
|
|
|
|
// Make sure the blts are between surface types that the
|
|
// driver will expect, otherwise the driver may fall-over
|
|
// if called with NtCrash or some other malicious program.
|
|
|
|
dwSrcCaps = peSurfaceSrc->ddsCaps.dwCaps;
|
|
dwDestCaps = peSurfaceDest->ddsCaps.dwCaps;
|
|
pCaps = &peDirectDrawGlobal->HalInfo.ddCaps;
|
|
|
|
// If the dest surface is the primary, DDraw will
|
|
// ask the kernel to Blt from system to video memory
|
|
// even if the driver doesn't specify this capability
|
|
// because it knows that the kernel can emulate it properly.
|
|
// The kernel used to set this cap, be we changed it because
|
|
// it was eating up too many handles and creating inefficiencies.
|
|
|
|
if (((dwSrcCaps & DDSCAPS_VIDEOMEMORY) &&
|
|
(dwDestCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
!(pCaps->dwVSBCaps & DDCAPS_BLT)) ||
|
|
|
|
((dwDestCaps & DDSCAPS_VIDEOMEMORY) &&
|
|
(dwSrcCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
(!(pCaps->dwSVBCaps & DDCAPS_BLT) &&
|
|
!(peSurfaceDest->fl & DD_SURFACE_FLAG_PRIMARY))) ||
|
|
|
|
((dwSrcCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
(dwDestCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
!(pCaps->dwSSBCaps & DDCAPS_BLT)))
|
|
{
|
|
WARNING("DxDdBlt: Illegal system memory surface");
|
|
return(dwRet);
|
|
}
|
|
}
|
|
|
|
// Make sure that we weren't given rectangle coordinates
|
|
// which might cause the driver to crash. Note that we
|
|
// don't allow inverting stretch blts:
|
|
|
|
if ((BltData.rDest.left >= 0) &&
|
|
(BltData.rDest.top >= 0) &&
|
|
(BltData.rDest.right <= (LONG) peSurfaceDest->wWidth) &&
|
|
(BltData.rDest.bottom <= (LONG) peSurfaceDest->wHeight) &&
|
|
(BltData.rDest.left < BltData.rDest.right) &&
|
|
(BltData.rDest.top < BltData.rDest.bottom))
|
|
{
|
|
// Make sure that the surfaces aren't associated
|
|
// with a PDEV whose mode has gone away.
|
|
//
|
|
// Also ensure that there are no outstanding
|
|
// surface locks if running on a brain-dead video
|
|
// card that crashes if the accelerator runs at
|
|
// the same time the frame buffer is accessed.
|
|
|
|
EDD_SHAREDEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
// We will return SURFACELOST when ...
|
|
//
|
|
// 1) This device is suspended.
|
|
// 2) The driver managed surface is managed by other device.
|
|
// 3) One of surface is losted.
|
|
// 4) The visible region has been changed when surface is primary.
|
|
|
|
if (peDirectDrawGlobal->bSuspended) // 1)
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
BltData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else if ((peSurfaceDest->fl & DD_SURFACE_FLAG_WRONG_DRIVER) ||
|
|
((peSurfaceSrc != NULL) &&
|
|
(peSurfaceSrc->fl & DD_SURFACE_FLAG_WRONG_DRIVER))) // 2)
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
BltData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else if ((peSurfaceDest->bLost) ||
|
|
((peSurfaceSrc != NULL) && (peSurfaceSrc->bLost))) // 3)
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
BltData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else if ((peSurfaceDest->fl & DD_SURFACE_FLAG_PRIMARY) &&
|
|
(peSurfaceDest->iVisRgnUniqueness != VISRGN_UNIQUENESS())) // 4)
|
|
{
|
|
// The VisRgn changed since the application last queried
|
|
// it; fail the call with a unique error code so that
|
|
// they know to requery the VisRgn and try again:
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
BltData.ddRVal = DDERR_VISRGNCHANGED;
|
|
}
|
|
else
|
|
{
|
|
if (peDirectDrawGlobal->HalInfo.ddCaps.dwCaps & DDCAPS_BLT)
|
|
{
|
|
BltData.lpDD = peDirectDrawGlobal;
|
|
|
|
// Give GDI a crack at doing the Blt. GDI may handle
|
|
// the blt only for the following cases:
|
|
//
|
|
// o When the blt occurs underneath a simulated sprite;
|
|
// o To emulate system-memory to video-memory HEL blts.
|
|
|
|
dwRet = dwDdBltViaGdi(peSurfaceDest,
|
|
peSurfaceSrc,
|
|
&BltData);
|
|
|
|
if (dwRet != DDHAL_DRIVER_HANDLED)
|
|
{
|
|
// This is the normal code path. First, exclude the
|
|
// mouse pointer and any other sprites if necessary:
|
|
|
|
DEVEXCLUDERECT dxo;
|
|
|
|
if (peSurfaceDest->fl & DD_SURFACE_FLAG_PRIMARY)
|
|
{
|
|
dxo.vExclude(peDirectDrawGlobal->hdev,
|
|
&BltData.rDest);
|
|
}
|
|
|
|
// Call the driver to do the blt:
|
|
|
|
dwRet = peDirectDrawGlobal->SurfaceCallBacks.
|
|
Blt(&BltData);
|
|
|
|
// If there was a flip pending, and the hardware
|
|
// blt succeeded, then unset the flag:
|
|
|
|
if ((peSurfaceDest->fl & DD_SURFACE_FLAG_FLIP_PENDING) &&
|
|
(dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(BltData.ddRVal == DD_OK))
|
|
{
|
|
peSurfaceDest->fl &= ~DD_SURFACE_FLAG_FLIP_PENDING;
|
|
}
|
|
}
|
|
|
|
// If the destination surface is the primary, update
|
|
// the bounds rect for this device:
|
|
|
|
if ((peSurfaceDest->fl & DD_SURFACE_FLAG_PRIMARY) &&
|
|
(dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(BltData.ddRVal == DD_OK))
|
|
{
|
|
// Union the current DirectDraw bounds rectangle
|
|
// with the destination blt rectangle:
|
|
//
|
|
// BltData.IsClipped will always be FALSE since
|
|
// it is currently unsupported, so we only
|
|
// consider BltData.rDest:
|
|
|
|
if (peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_BOUNDS_SET)
|
|
{
|
|
if (BltData.rDest.left < peDirectDrawGlobal->rclBounds.left)
|
|
peDirectDrawGlobal->rclBounds.left = BltData.rDest.left;
|
|
|
|
if (BltData.rDest.top < peDirectDrawGlobal->rclBounds.top)
|
|
peDirectDrawGlobal->rclBounds.top = BltData.rDest.top;
|
|
|
|
if (BltData.rDest.right > peDirectDrawGlobal->rclBounds.right)
|
|
peDirectDrawGlobal->rclBounds.right = BltData.rDest.right;
|
|
|
|
if (BltData.rDest.bottom > peDirectDrawGlobal->rclBounds.bottom)
|
|
peDirectDrawGlobal->rclBounds.bottom = BltData.rDest.bottom;
|
|
}
|
|
else
|
|
{
|
|
peDirectDrawGlobal->rclBounds = BltData.rDest;
|
|
peDirectDrawGlobal->fl |= DD_GLOBAL_FLAG_BOUNDS_SET;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdBlt: Invalid destination rectangle\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdBlt: Invalid dwFlags\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdBlt: Couldn't lock destination surface\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(&puBltData->ddRVal, BltData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdFlip
|
|
*
|
|
* DirectDraw flip.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
DWORD
|
|
APIENTRY
|
|
DxDdFlip(
|
|
HANDLE hSurfaceCurrent,
|
|
HANDLE hSurfaceTarget,
|
|
HANDLE hSurfaceCurrentLeft,
|
|
HANDLE hSurfaceTargetLeft,
|
|
PDD_FLIPDATA puFlipData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_FLIPDATA FlipData;
|
|
|
|
__try
|
|
{
|
|
FlipData = ProbeAndReadStructure(puFlipData, DD_FLIPDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
FlipData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_SURFACE* peSurfaceCurrent;
|
|
EDD_SURFACE* peSurfaceCurrentLeft;
|
|
EDD_SURFACE* peSurfaceTarget;
|
|
EDD_SURFACE* peSurfaceTargetLeft;
|
|
EDD_LOCK_SURFACE eLockSurfaceCurrent;
|
|
EDD_LOCK_SURFACE eLockSurfaceCurrentLeft;
|
|
EDD_LOCK_SURFACE eLockSurfaceTarget;
|
|
EDD_LOCK_SURFACE eLockSurfaceTargetLeft;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peSurfaceCurrent = eLockSurfaceCurrent.peLock(hSurfaceCurrent);
|
|
peSurfaceTarget = eLockSurfaceTarget.peLock(hSurfaceTarget);
|
|
|
|
BOOL bLeftSurfaceOk=FALSE;
|
|
|
|
if (FlipData.dwFlags & DDFLIP_STEREO)
|
|
{
|
|
peSurfaceTargetLeft = eLockSurfaceTargetLeft.peLock(hSurfaceTargetLeft);
|
|
peSurfaceCurrentLeft = eLockSurfaceCurrentLeft.peLock(hSurfaceCurrentLeft);
|
|
|
|
// first check if left surface is ok
|
|
// in stereo mode
|
|
|
|
if ((peSurfaceCurrentLeft != NULL) &&
|
|
(peSurfaceTargetLeft != NULL) &&
|
|
(peSurfaceCurrent != peSurfaceTargetLeft) &&
|
|
(peSurfaceCurrent != peSurfaceCurrentLeft) &&
|
|
(peSurfaceTarget != peSurfaceTargetLeft) &&
|
|
(peSurfaceTarget != peSurfaceCurrentLeft) &&
|
|
(peSurfaceCurrentLeft != peSurfaceTargetLeft) &&
|
|
(peSurfaceCurrent->peDirectDrawLocal ==
|
|
peSurfaceTargetLeft->peDirectDrawLocal) &&
|
|
(peSurfaceCurrent->peDirectDrawLocal ==
|
|
peSurfaceCurrentLeft->peDirectDrawLocal)
|
|
)
|
|
{
|
|
bLeftSurfaceOk=TRUE;
|
|
} else
|
|
{
|
|
peSurfaceTargetLeft = NULL;
|
|
peSurfaceCurrentLeft = NULL;
|
|
}
|
|
} else
|
|
{
|
|
peSurfaceTargetLeft = NULL;
|
|
peSurfaceCurrentLeft = NULL;
|
|
bLeftSurfaceOk=TRUE;
|
|
}
|
|
|
|
// Make sure surfaces belong to the same DirectDraw object and no
|
|
// bad commands are specified:
|
|
|
|
if ( bLeftSurfaceOk &&
|
|
(peSurfaceCurrent != NULL) &&
|
|
(peSurfaceTarget != NULL) &&
|
|
(peSurfaceCurrent->peDirectDrawLocal ==
|
|
peSurfaceTarget->peDirectDrawLocal) &&
|
|
((FlipData.dwFlags & ~DDFLIP_VALID) == 0))
|
|
{
|
|
peDirectDrawGlobal = peSurfaceCurrent->peDirectDrawGlobal;
|
|
|
|
// Flipping to the same surface is OK as long as it's an overlay
|
|
// and the ODD/EVEN flag is specified and supported by the driver
|
|
|
|
if ((peSurfaceCurrent != peSurfaceTarget) ||
|
|
((FlipData.dwFlags & (DDFLIP_EVEN|DDFLIP_ODD)) &&
|
|
( peSurfaceCurrent->ddsCaps.dwCaps & DDSCAPS_OVERLAY ) &&
|
|
(peDirectDrawGlobal->HalInfo.ddCaps.dwCaps2 & DDCAPS2_CANFLIPODDEVEN)))
|
|
{
|
|
|
|
// Make sure that the target is flippable:
|
|
if (peSurfaceCurrentLeft != NULL && peSurfaceTargetLeft != NULL)
|
|
{
|
|
if (!((peSurfaceCurrent->wHeight == peSurfaceTargetLeft->wHeight) &&
|
|
(peSurfaceCurrent->wWidth == peSurfaceTargetLeft->wWidth) &&
|
|
(peSurfaceCurrentLeft->wHeight == peSurfaceTargetLeft->wHeight) &&
|
|
(peSurfaceCurrentLeft->wWidth == peSurfaceTargetLeft->wWidth) &&
|
|
!(peSurfaceCurrentLeft->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
!(peSurfaceTargetLeft->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)))
|
|
{
|
|
bLeftSurfaceOk = FALSE;
|
|
}
|
|
}
|
|
|
|
if ( bLeftSurfaceOk &&
|
|
(peDirectDrawGlobal->SurfaceCallBacks.dwFlags & DDHAL_SURFCB32_FLIP) &&
|
|
(peSurfaceCurrent->wHeight == peSurfaceTarget->wHeight) &&
|
|
(peSurfaceCurrent->wWidth == peSurfaceTarget->wWidth) &&
|
|
!(peSurfaceCurrent->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
!(peSurfaceTarget->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
|
|
{
|
|
FlipData.lpDD = peDirectDrawGlobal;
|
|
FlipData.lpSurfCurr = peSurfaceCurrent;
|
|
FlipData.lpSurfCurrLeft = peSurfaceCurrentLeft;
|
|
FlipData.lpSurfTarg = peSurfaceTarget;
|
|
FlipData.lpSurfTargLeft = peSurfaceTargetLeft;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (peSurfaceCurrentLeft != NULL && peSurfaceTargetLeft != NULL)
|
|
{
|
|
bLeftSurfaceOk =!(peSurfaceCurrentLeft->bLost) &&
|
|
!(peSurfaceTargetLeft->bLost);
|
|
}
|
|
|
|
if (!bLeftSurfaceOk ||
|
|
(peSurfaceCurrent->bLost) ||
|
|
(peSurfaceTarget->bLost))
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
FlipData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else
|
|
{
|
|
dwRet = peDirectDrawGlobal->SurfaceCallBacks.Flip(&FlipData);
|
|
|
|
// Remember this surface so that if it gets deleted, we can
|
|
// flip back to the GDI surface, assuming it's not an
|
|
// overlay surface:
|
|
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(FlipData.ddRVal == DD_OK))
|
|
{
|
|
// Keep track of the hardware flip on this surface so if
|
|
// we do emulated blts to it, we will wait for the flip
|
|
// to complete first:
|
|
|
|
if(peSurfaceCurrent != peSurfaceTarget)
|
|
{
|
|
peSurfaceCurrent->fl |= DD_SURFACE_FLAG_FLIP_PENDING;
|
|
}
|
|
|
|
if(peSurfaceTarget->ddsCaps.dwCaps & DDSCAPS_OVERLAY)
|
|
{
|
|
if(peSurfaceCurrent->fl & DD_SURFACE_FLAG_UPDATE_OVERLAY_CALLED)
|
|
{
|
|
peSurfaceTarget->fl |= DD_SURFACE_FLAG_UPDATE_OVERLAY_CALLED;
|
|
if(peSurfaceCurrent != peSurfaceTarget)
|
|
{
|
|
peSurfaceCurrent->fl &= ~DD_SURFACE_FLAG_UPDATE_OVERLAY_CALLED;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
peSurfaceCurrent->ddsCaps.dwCaps &= ~DDSCAPS_PRIMARYSURFACE;
|
|
peSurfaceTarget->ddsCaps.dwCaps |= DDSCAPS_PRIMARYSURFACE;
|
|
|
|
peDirectDrawGlobal->peSurfaceCurrent = peSurfaceTarget;
|
|
if (peSurfaceCurrent->fl & DD_SURFACE_FLAG_PRIMARY)
|
|
{
|
|
peDirectDrawGlobal->peSurfacePrimary
|
|
= peSurfaceCurrent;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdFlip: Non-flippable surface\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdFlip: Invalid flip to same surface\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdFlip: Invalid surfaces or dwFlags\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(&puFlipData->ddRVal, FlipData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdLock
|
|
*
|
|
* DirectDraw function to return a user-mode pointer to the screen or
|
|
* off-screen surface.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdLock(
|
|
HANDLE hSurface,
|
|
PDD_LOCKDATA puLockData,
|
|
HDC hdcClip
|
|
)
|
|
{
|
|
DD_LOCKDATA LockData;
|
|
|
|
__try
|
|
{
|
|
LockData = ProbeAndReadStructure(puLockData, DD_LOCKDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
|
|
LockData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_SURFACE* peSurface;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
|
|
// Note that we have to let down DDLOCK_READONLY, DDLOCK_WRITE,
|
|
// and DDLOCK_WAIT for compatibility. Note also that a
|
|
// DDLOCK_SURFACEMEMORY flag also gets passed down by default.
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if ((peSurface != NULL) &&
|
|
((LockData.dwFlags & ~(DDLOCK_VALID)) == 0))
|
|
{
|
|
LockData.lpSurfData = pDdLockSurfaceOrBuffer(peSurface,
|
|
LockData.bHasRect,
|
|
&LockData.rArea,
|
|
// We remove the wait flag since it better to spin in user mode
|
|
LockData.dwFlags & (~DDLOCK_WAIT),
|
|
&LockData.ddRVal);
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdLock: Invalid surface or flags\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
|
|
{
|
|
ProbeAndWriteHandle(&puLockData->lpSurfData, LockData.lpSurfData);
|
|
ProbeAndWriteRVal(&puLockData->ddRVal, LockData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
// This function must always return DDHAL_DRIVER_HANDLED, otherwise
|
|
// DirectDraw will simply use the 'fpVidMem' value, which on NT is
|
|
// an offset and not a pointer:
|
|
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdUnlock
|
|
*
|
|
* DirectDraw unlock.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdUnlock(
|
|
HANDLE hSurface,
|
|
PDD_UNLOCKDATA puUnlockData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_UNLOCKDATA UnlockData;
|
|
|
|
__try
|
|
{
|
|
UnlockData = ProbeAndReadStructure(puUnlockData, DD_UNLOCKDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
|
|
UnlockData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_SURFACE* peSurface;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if (peSurface != NULL)
|
|
{
|
|
if (bDdUnlockSurfaceOrBuffer(peSurface))
|
|
{
|
|
UnlockData.ddRVal = DD_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdUnlock: Invalid surface\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(&puUnlockData->ddRVal, UnlockData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdLockD3D
|
|
*
|
|
* DirectDraw function to return a user-mode pointer to the screen or
|
|
* off-screen surface.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdLockD3D(
|
|
HANDLE hSurface,
|
|
PDD_LOCKDATA puLockData
|
|
)
|
|
{
|
|
DD_LOCKDATA LockData;
|
|
|
|
__try
|
|
{
|
|
LockData = ProbeAndReadStructure(puLockData, DD_LOCKDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
|
|
LockData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_SURFACE* peSurface;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
|
|
// Note that we have to let down DDLOCK_READONLY, DDLOCK_WRITE,
|
|
// and DDLOCK_WAIT for compatibility. Note also that a
|
|
// DDLOCK_SURFACEMEMORY flag also gets passed down by default.
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if ((peSurface != NULL) &&
|
|
((LockData.dwFlags & ~(DDLOCK_VALID)) == 0))
|
|
{
|
|
LockData.lpSurfData = pDdLockSurfaceOrBuffer(peSurface,
|
|
LockData.bHasRect,
|
|
&LockData.rArea,
|
|
// We remove the wait flag since it better to spin in user mode
|
|
LockData.dwFlags & (~DDLOCK_WAIT),
|
|
&LockData.ddRVal);
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdLockD3D: Invalid surface or flags\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
|
|
{
|
|
ProbeAndWriteHandle(&puLockData->lpSurfData, LockData.lpSurfData);
|
|
ProbeAndWriteRVal(&puLockData->ddRVal, LockData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
// This function must always return DDHAL_DRIVER_HANDLED, otherwise
|
|
// DirectDraw will simply use the 'fpVidMem' value, which on NT is
|
|
// an offset and not a pointer:
|
|
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdUnlockD3D
|
|
*
|
|
* DirectDraw unlock.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdUnlockD3D(
|
|
HANDLE hSurface,
|
|
PDD_UNLOCKDATA puUnlockData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_UNLOCKDATA UnlockData;
|
|
|
|
__try
|
|
{
|
|
UnlockData = ProbeAndReadStructure(puUnlockData, DD_UNLOCKDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
|
|
UnlockData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_SURFACE* peSurface;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if (peSurface != NULL)
|
|
{
|
|
if (bDdUnlockSurfaceOrBuffer(peSurface))
|
|
{
|
|
UnlockData.ddRVal = DD_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdUnlockD3D: Invalid surface\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(&puUnlockData->ddRVal, UnlockData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdGetFlipStatus
|
|
*
|
|
* DirectDraw API to get the page-flip status.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdGetFlipStatus(
|
|
HANDLE hSurface,
|
|
PDD_GETFLIPSTATUSDATA puGetFlipStatusData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETFLIPSTATUSDATA GetFlipStatusData;
|
|
|
|
__try
|
|
{
|
|
GetFlipStatusData = ProbeAndReadStructure(puGetFlipStatusData,
|
|
DD_GETFLIPSTATUSDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
GetFlipStatusData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_SURFACE* peSurface;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if ((peSurface != NULL) &&
|
|
!(peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
((GetFlipStatusData.dwFlags & ~(DDGFS_CANFLIP
|
|
| DDGFS_ISFLIPDONE)) == 0))
|
|
{
|
|
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
|
|
|
|
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags &
|
|
DDHAL_SURFCB32_GETFLIPSTATUS)
|
|
{
|
|
GetFlipStatusData.lpDD = peDirectDrawGlobal;
|
|
GetFlipStatusData.lpDDSurface = peSurface;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (peSurface->bLost)
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
GetFlipStatusData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
SurfaceCallBacks.GetFlipStatus(&GetFlipStatusData);
|
|
|
|
// If a flip was pending, and has completed, then turn off
|
|
// the flag:
|
|
|
|
if ((peSurface->fl & DD_SURFACE_FLAG_FLIP_PENDING) &&
|
|
(GetFlipStatusData.dwFlags & DDGFS_ISFLIPDONE) &&
|
|
(dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(GetFlipStatusData.ddRVal == DD_OK))
|
|
{
|
|
peSurface->fl &= ~DD_SURFACE_FLAG_FLIP_PENDING;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetFlipStatus: Invalid surface or dwFlags\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(&puGetFlipStatusData->ddRVal,
|
|
GetFlipStatusData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdGetBltStatus
|
|
*
|
|
* DirectDraw API to get the accelerator's accelerator status.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdGetBltStatus(
|
|
HANDLE hSurface,
|
|
PDD_GETBLTSTATUSDATA puGetBltStatusData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETBLTSTATUSDATA GetBltStatusData;
|
|
|
|
__try
|
|
{
|
|
GetBltStatusData = ProbeAndReadStructure(puGetBltStatusData,
|
|
DD_GETBLTSTATUSDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
GetBltStatusData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_SURFACE* peSurface;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if ((peSurface != NULL) &&
|
|
!(peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
((GetBltStatusData.dwFlags & ~(DDGBS_CANBLT
|
|
| DDGBS_ISBLTDONE)) == 0))
|
|
{
|
|
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
|
|
|
|
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags &
|
|
DDHAL_SURFCB32_GETBLTSTATUS)
|
|
{
|
|
GetBltStatusData.lpDD = peDirectDrawGlobal;
|
|
GetBltStatusData.lpDDSurface = peSurface;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (peSurface->bLost)
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
GetBltStatusData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
SurfaceCallBacks.GetBltStatus(&GetBltStatusData);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetBltStatus: Invalid surface or dwFlags\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(&puGetBltStatusData->ddRVal, GetBltStatusData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdWaitForVerticalBlank
|
|
*
|
|
* DirectDraw API to wait for vertical blank.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdWaitForVerticalBlank(
|
|
HANDLE hDirectDraw,
|
|
PDD_WAITFORVERTICALBLANKDATA puWaitForVerticalBlankData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_WAITFORVERTICALBLANKDATA WaitForVerticalBlankData;
|
|
|
|
__try
|
|
{
|
|
WaitForVerticalBlankData =
|
|
ProbeAndReadStructure(puWaitForVerticalBlankData,
|
|
DD_WAITFORVERTICALBLANKDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
WaitForVerticalBlankData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
|
|
if ((peDirectDrawLocal != NULL) &&
|
|
((WaitForVerticalBlankData.dwFlags & ~(DDWAITVB_I_TESTVB
|
|
| DDWAITVB_BLOCKBEGIN
|
|
| DDWAITVB_BLOCKBEGINEVENT
|
|
| DDWAITVB_BLOCKEND)) == 0) &&
|
|
(WaitForVerticalBlankData.dwFlags != 0))
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
if (peDirectDrawGlobal->CallBacks.dwFlags &
|
|
DDHAL_CB32_WAITFORVERTICALBLANK)
|
|
{
|
|
WaitForVerticalBlankData.lpDD = peDirectDrawGlobal;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (peDirectDrawGlobal->bSuspended)
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
WaitForVerticalBlankData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
CallBacks.WaitForVerticalBlank(&WaitForVerticalBlankData);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdWaitForVerticalBlank: Invalid object or dwFlags\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(&puWaitForVerticalBlankData->ddRVal,
|
|
WaitForVerticalBlankData.ddRVal);
|
|
ProbeAndWriteUlong(&puWaitForVerticalBlankData->bIsInVB,
|
|
WaitForVerticalBlankData.bIsInVB);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD dwDdCanCreateSurfaceOrBuffer
|
|
*
|
|
* Handles DxDdCanCreateSurface and DxDdCanCreateD3DBuffer.
|
|
*
|
|
* 3-Feb-1998 -by- Drew Bliss [drewb]
|
|
* Merged common code from calling routines.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
dwDdCanCreateSurfaceOrBuffer(
|
|
BOOL bSurface,
|
|
HANDLE hDirectDraw,
|
|
PDD_CANCREATESURFACEDATA puCanCreateSurfaceData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_CANCREATESURFACEDATA CanCreateSurfaceData;
|
|
DDSURFACEDESC2* puSurfaceDescription;
|
|
DDSURFACEDESC2 SurfaceDescription;
|
|
|
|
__try
|
|
{
|
|
CanCreateSurfaceData = ProbeAndReadStructure(puCanCreateSurfaceData,
|
|
DD_CANCREATESURFACEDATA);
|
|
|
|
puSurfaceDescription = (DDSURFACEDESC2 *)CanCreateSurfaceData.lpDDSurfaceDesc;
|
|
|
|
SurfaceDescription = ProbeAndReadStructure(puSurfaceDescription,
|
|
DDSURFACEDESC2);
|
|
|
|
CanCreateSurfaceData.lpDDSurfaceDesc = (DDSURFACEDESC*)&SurfaceDescription;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
// All video memory heaps are handled in the kernel so if
|
|
// this routine cannot create a surface then user-mode can't
|
|
// either. Always returns DRIVER_HANDLED to enforce this.
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
CanCreateSurfaceData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
// Choose function to call.
|
|
PDD_CANCREATESURFACE pfnCanCreate;
|
|
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (bSurface)
|
|
{
|
|
pfnCanCreate =
|
|
(peDirectDrawGlobal->CallBacks.dwFlags &
|
|
DDHAL_CB32_CANCREATESURFACE) ?
|
|
peDirectDrawGlobal->CallBacks.CanCreateSurface :
|
|
NULL;
|
|
}
|
|
else
|
|
{
|
|
pfnCanCreate =
|
|
peDirectDrawGlobal->D3dBufCallbacks.CanCreateD3DBuffer;
|
|
}
|
|
|
|
if (pfnCanCreate != NULL)
|
|
{
|
|
CanCreateSurfaceData.lpDD = peDirectDrawGlobal;
|
|
|
|
if (!peDirectDrawGlobal->bSuspended)
|
|
{
|
|
dwRet = pfnCanCreate(&CanCreateSurfaceData);
|
|
}
|
|
else
|
|
{
|
|
CanCreateSurfaceData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("dwDdCanCreateSurface: Driver doesn't hook call\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("dwDdCanCreateSurface: 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(&puCanCreateSurfaceData->ddRVal,
|
|
CanCreateSurfaceData.ddRVal);
|
|
ProbeAndWriteStructure(puSurfaceDescription,
|
|
SurfaceDescription,
|
|
DDSURFACEDESC);
|
|
// Driver can update ddpfPixelFormat.dwYUVBitCount
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdCanCreateSurface
|
|
*
|
|
* Queries the driver to determine whether it can support a DirectDraw
|
|
* surface that is different from the primary display.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdCanCreateSurface(
|
|
HANDLE hDirectDraw,
|
|
PDD_CANCREATESURFACEDATA puCanCreateSurfaceData
|
|
)
|
|
{
|
|
return dwDdCanCreateSurfaceOrBuffer(TRUE, hDirectDraw,
|
|
puCanCreateSurfaceData);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdCanCreateD3DBuffer
|
|
*
|
|
* Queries the driver to determine whether it can support a given D3D Buffer
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdCanCreateD3DBuffer(
|
|
HANDLE hDirectDraw,
|
|
PDD_CANCREATESURFACEDATA puCanCreateSurfaceData
|
|
)
|
|
{
|
|
return dwDdCanCreateSurfaceOrBuffer(FALSE, hDirectDraw,
|
|
puCanCreateSurfaceData);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HRESULT hrDdCommitAgpSurface
|
|
*
|
|
* Ensures that user-mode addresses are reserved in the current process
|
|
* and commits pages for the given surface.
|
|
*
|
|
* 7-May-1998 -by- Drew Bliss [drewb]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HRESULT
|
|
hrDdCommitAgpSurface(
|
|
EDD_SURFACE* peSurface,
|
|
DWORD dwSurfaceSize
|
|
)
|
|
{
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_VMEMMAPPING* peMap;
|
|
VIDEOMEMORY* pvmHeap;
|
|
DWORD iHeapIndex;
|
|
|
|
peDirectDrawLocal = peSurface->peDirectDrawLocal;
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
pvmHeap = peSurface->lpVidMemHeap;
|
|
|
|
ASSERTGDI(peDirectDrawLocal->ppeMapAgp != NULL,
|
|
"Committing AGP surface with no heaps\n");
|
|
|
|
iHeapIndex = (DWORD) (pvmHeap - peDirectDrawGlobal->pvmList);
|
|
peMap = peDirectDrawLocal->ppeMapAgp[iHeapIndex];
|
|
if (peMap == NULL)
|
|
{
|
|
MapAllAgpHeaps(peDirectDrawLocal);
|
|
peMap = peDirectDrawLocal->ppeMapAgp[iHeapIndex];
|
|
if (peMap == NULL)
|
|
{
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
peSurface->fpVidMem =
|
|
(FLATPTR)(peMap->pvVirtAddr) +
|
|
(peSurface->fpHeapOffset - pvmHeap->fpStart);
|
|
return DD_OK;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HRESULT hrDdAllocSurface
|
|
*
|
|
* Allocates memory for the given surface.
|
|
*
|
|
* 3-Feb-1998 -by- Drew Bliss [drewb]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HRESULT
|
|
hrDdAllocSurface(
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal,
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
|
|
EDD_SURFACE* peSurface
|
|
)
|
|
{
|
|
HRESULT hr = DDERR_OUTOFVIDEOMEMORY;
|
|
BOOL bAllowNewPitch = TRUE;
|
|
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
ASSERTGDI(!(peSurface->ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY |
|
|
DDSCAPS_PRIMARYSURFACE)),
|
|
"hrDdAllocSurface: System-memory or primary request");
|
|
|
|
// If 'fpVidMem' is DDHAL_PLEASEALLOC_USERMEM, that means
|
|
// the driver wants us to allocate a chunk of user-mode
|
|
// memory on the driver's behalf:
|
|
|
|
if (peSurface->fpVidMem == DDHAL_PLEASEALLOC_USERMEM)
|
|
{
|
|
// The driver was involved in this surface creation so
|
|
// mark it as such.
|
|
peSurface->fl |= DD_SURFACE_FLAG_DRIVER_CREATED;
|
|
|
|
peSurface->fpVidMem =
|
|
(FLATPTR) EngAllocUserMem(peSurface->dwUserMemSize, 'pddG');
|
|
if (peSurface->fpVidMem != 0)
|
|
{
|
|
peSurface->fl |= DD_SURFACE_FLAG_UMEM_ALLOCATED;
|
|
hr = DD_OK;
|
|
|
|
DDKHEAP(("DDKHEAP: New um %08X, surf %X (%X)\n",
|
|
peSurface->fpVidMem, peSurface->hGet(), peSurface));
|
|
}
|
|
else
|
|
{
|
|
hr = DDERR_OUTOFMEMORY;
|
|
}
|
|
|
|
// FIX: WINBUG #388284
|
|
//
|
|
// - MATROX G200: STRESS: dxg ASSERT when YV12 overlay surface gets created in system memory
|
|
//
|
|
// Set bAllowNewPitch to FALSE to avoid hitting assertion in below.
|
|
//
|
|
// Matrox G200 does not support YU12 overlay surface format, but they want to
|
|
// support this format for application compatibility, thus video driver ask us
|
|
// to allocate YU12 overlay surface in system memory, so that they can Blt
|
|
// with software emulation.
|
|
|
|
bAllowNewPitch = FALSE;
|
|
}
|
|
else
|
|
{
|
|
DWORD dwWidth, dwHeight;
|
|
DWORD dwSurfaceSize;
|
|
|
|
if (peSurface->fpVidMem == DDHAL_PLEASEALLOC_BLOCKSIZE)
|
|
{
|
|
// The driver wants a surface of a particular size to be
|
|
// allocated.
|
|
dwWidth = peSurface->dwBlockSizeX;
|
|
dwHeight = peSurface->dwBlockSizeY;
|
|
bAllowNewPitch = FALSE;
|
|
|
|
// The driver was involved in this surface creation so
|
|
// mark it as such.
|
|
peSurface->fl |= DD_SURFACE_FLAG_DRIVER_CREATED;
|
|
}
|
|
else
|
|
{
|
|
// The driver didn't specify a size so determine it from
|
|
// the surface dimensions.
|
|
|
|
if (peSurface->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER)
|
|
{
|
|
// Execute buffers are long, thin surfaces for the purposes
|
|
// of VM allocation.
|
|
dwWidth = peSurface->dwLinearSize;
|
|
dwHeight = 1;
|
|
}
|
|
else
|
|
{
|
|
// This lPitch may have been expanded by ComputePitch
|
|
// to cover global alignment restrictions.
|
|
dwWidth = labs(peSurface->lPitch);
|
|
dwHeight = peSurface->wHeight;
|
|
}
|
|
|
|
// The driver didn't do anything special for this allocation
|
|
// so don't call it when the surface is destroyed.
|
|
}
|
|
|
|
DWORD dwFlags = 0;
|
|
|
|
// In user mode DDHA_SKIPRECTANGULARHEAPS keys off of
|
|
// DDRAWISURFGBL_LATEALLOCATELINEAR. Right now we just leave
|
|
// it off.
|
|
|
|
if (peDirectDrawGlobal->HalInfo.ddCaps.dwCaps2 &
|
|
DDCAPS2_NONLOCALVIDMEMCAPS)
|
|
{
|
|
dwFlags |= DDHA_ALLOWNONLOCALMEMORY;
|
|
}
|
|
|
|
if (peDirectDrawGlobal->D3dDriverData.hwCaps.dwDevCaps &
|
|
D3DDEVCAPS_TEXTURENONLOCALVIDMEM)
|
|
{
|
|
dwFlags |= DDHA_ALLOWNONLOCALTEXTURES;
|
|
}
|
|
|
|
LONG lNewPitch = 0;
|
|
DWORD dwNewCaps = 0;
|
|
DWORD dwRet;
|
|
DD_FREEDRIVERMEMORYDATA FreeDriverMemoryData;
|
|
|
|
do {
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
|
|
// Attempt to allocate the surface.
|
|
peSurface->fpHeapOffset =
|
|
DdHeapAlloc(peDirectDrawGlobal->dwNumHeaps,
|
|
peDirectDrawGlobal->pvmList,
|
|
AGP_HDEV(peDirectDrawGlobal),
|
|
&peDirectDrawGlobal->HalInfo.vmiData,
|
|
dwWidth,
|
|
dwHeight,
|
|
peSurface,
|
|
dwFlags,
|
|
&peSurface->lpVidMemHeap,
|
|
&lNewPitch,
|
|
&dwNewCaps,
|
|
&dwSurfaceSize);
|
|
|
|
// If the surface could not be allocated, try calling the
|
|
// driver to see if it can free up some room (such as by
|
|
// getting rid of GDI surfaces).
|
|
if ((peSurface->fpHeapOffset == 0) &&
|
|
!(peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->NTCallBacks.dwFlags &
|
|
DDHAL_NTCB32_FREEDRIVERMEMORY))
|
|
{
|
|
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
|
|
|
|
FreeDriverMemoryData.lpDD = peDirectDrawGlobal;
|
|
FreeDriverMemoryData.lpDDSurface = peSurface;
|
|
FreeDriverMemoryData.ddRVal = DDERR_GENERIC;
|
|
|
|
dwRet = peDirectDrawGlobal->NTCallBacks.
|
|
FreeDriverMemory(&FreeDriverMemoryData);
|
|
}
|
|
} while ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(FreeDriverMemoryData.ddRVal == DD_OK));
|
|
|
|
// If the surface could not be allocated with the optimal caps,
|
|
// try allocating with the alternate caps.
|
|
if (peSurface->fpHeapOffset == 0)
|
|
{
|
|
peSurface->fpHeapOffset =
|
|
DdHeapAlloc(peDirectDrawGlobal->dwNumHeaps,
|
|
peDirectDrawGlobal->pvmList,
|
|
AGP_HDEV(peDirectDrawGlobal),
|
|
&peDirectDrawGlobal->HalInfo.vmiData,
|
|
dwWidth,
|
|
dwHeight,
|
|
peSurface,
|
|
dwFlags | DDHA_USEALTCAPS,
|
|
&peSurface->lpVidMemHeap,
|
|
&lNewPitch,
|
|
&dwNewCaps,
|
|
&dwSurfaceSize);
|
|
}
|
|
|
|
if (peSurface->fpHeapOffset != 0)
|
|
{
|
|
// If this surface was allocated from an AGP heap then
|
|
// we must make sure that the heap has a user-mode mapping
|
|
// for this process and we must commit the necessary user-mode
|
|
// pages.
|
|
if (dwNewCaps & DDSCAPS_NONLOCALVIDMEM)
|
|
{
|
|
hr = hrDdCommitAgpSurface(peSurface, dwSurfaceSize);
|
|
|
|
if (hr != DD_OK)
|
|
{
|
|
DxDdHeapVidMemFree(peSurface->lpVidMemHeap->lpHeap,
|
|
peSurface->fpHeapOffset);
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
peSurface->fpVidMem = peSurface->fpHeapOffset;
|
|
}
|
|
|
|
hr = DD_OK;
|
|
peSurface->fl |= DD_SURFACE_FLAG_VMEM_ALLOCATED;
|
|
|
|
// The particular heap that was used for the allocation may
|
|
// modify certain aspects of the surface. Update the surface
|
|
// to reflect any changes.
|
|
//
|
|
// The stride is not relevant for an execute buffer so we don't
|
|
// override it in that case.
|
|
|
|
if (lNewPitch != 0 && bAllowNewPitch &&
|
|
!(peSurface->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
|
|
{
|
|
peSurface->lPitch = lNewPitch;
|
|
}
|
|
|
|
peSurface->ddsCaps.dwCaps |= dwNewCaps;
|
|
|
|
ASSERTGDI((peSurface->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER) ||
|
|
peSurface->lPitch > 0,
|
|
"Unexpected negative surface pitch");
|
|
ASSERTGDI((peSurface->fl & DD_SURFACE_FLAG_DRIVER_CREATED) ||
|
|
((peSurface->ddpfSurface.dwFlags &
|
|
(DDPF_RGB | DDPF_ZBUFFER)) &&
|
|
(peSurface->ddsCaps.dwCaps & DDSCAPS_OVERLAY) == 0),
|
|
"Unexpected non-driver surface type");
|
|
|
|
DDKHEAP(("DDKHEAP: New vm %08X, o %08X, heap %X, surf %X (%X)\n",
|
|
peSurface->fpVidMem, peSurface->fpHeapOffset,
|
|
peSurface->lpVidMemHeap->lpHeap,
|
|
peSurface->hGet(), peSurface));
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
if (hr == DD_OK &&
|
|
(peSurface->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER) == 0)
|
|
{
|
|
ASSERTGDI((peSurface->fpVidMem & 3) == 0 &&
|
|
(peSurface->lPitch & 3) == 0,
|
|
"Unaligned surface pointer or pitch");
|
|
ASSERTGDI(ABS(peSurface->lPitch) <= 4 * DD_MAXIMUM_COORDINATE,
|
|
"Pitch out of range");
|
|
|
|
// The width in bytes must not be more than the pitch.
|
|
// There are weird cases when this is actually valid (e.g. planar YUV formats), but in all
|
|
// such cases it would involve FOURCCs and the driver telling us which block size to allocate.
|
|
ASSERTGDI((peSurface->wWidth * peSurface->ddpfSurface.dwRGBBitCount <=
|
|
(ULONG) 8 * ABS(peSurface->lPitch) ||
|
|
(!bAllowNewPitch && (peSurface->ddpfSurface.dwFlags & DDPF_FOURCC))),
|
|
"Pitch less than width");
|
|
}
|
|
#endif
|
|
|
|
return hr;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD dwDdCreateSurfaceOrBuffer
|
|
*
|
|
* Handles DxDdCreateSurface and DxDdCreateD3DBuffer.
|
|
*
|
|
* 3-Feb-1998 -by- Drew Bliss [drewb]
|
|
* Merged common code from calling functions.
|
|
\**************************************************************************/
|
|
|
|
DWORD dwDdCreateSurfaceOrBuffer(
|
|
HANDLE hDirectDraw,
|
|
HANDLE* phSurfaceHandles,
|
|
DDSURFACEDESC* puSurfaceDescription,
|
|
DD_SURFACE_GLOBAL* puSurfaceGlobalData,
|
|
DD_SURFACE_LOCAL* puSurfaceLocalData,
|
|
DD_SURFACE_MORE* puSurfaceMoreData,
|
|
DD_CREATESURFACEDATA* puCreateSurfaceData,
|
|
HANDLE* puhReturnSurfaceHandles
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_CREATESURFACEDATA CreateSurfaceData;
|
|
DDSURFACEDESC2 SurfaceDescription;
|
|
ULONG dwNumToCreate;
|
|
HANDLE hSecureSurfaceHandles;
|
|
HANDLE hSecureGlobals;
|
|
HANDLE hSecureLocals;
|
|
HANDLE hSecureMore;
|
|
HANDLE hSecureReturn;
|
|
ULONG cjHandles;
|
|
ULONG cjGlobals;
|
|
ULONG cjLocals;
|
|
ULONG cjMore;
|
|
ULONG i;
|
|
ULONG j;
|
|
ULONG k;
|
|
BOOL bAutomicCreate;
|
|
BOOL bNotifyCreation;
|
|
ULONG dwStart;
|
|
ULONG dwEnd;
|
|
|
|
__try
|
|
{
|
|
CreateSurfaceData = ProbeAndReadStructure(puCreateSurfaceData,
|
|
DD_CREATESURFACEDATA);
|
|
SurfaceDescription = ProbeAndReadStructure((DDSURFACEDESC2*)puSurfaceDescription,
|
|
DDSURFACEDESC2);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
|
|
// All video memory heaps are handled in the kernel so if
|
|
// this routine cannot create a surface then user-mode can't
|
|
// either. Always returns DRIVER_HANDLED to enforce this.
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
CreateSurfaceData.ddRVal = DDERR_GENERIC;
|
|
dwNumToCreate = CreateSurfaceData.dwSCnt;
|
|
|
|
EDD_SURFACE** peSurface;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
DD_SURFACE_LOCAL* pSurfaceLocal;
|
|
BOOL bKeepSurface;
|
|
PDD_CREATESURFACE pfnCreate;
|
|
|
|
DD_SURFACE_LOCAL** pSList = NULL;
|
|
EDD_SURFACE* peSurfaceOnStack = NULL;
|
|
BOOL bAnyType = TRUE;
|
|
DWORD dwForceMemType = 0;
|
|
|
|
peSurface = NULL;
|
|
bKeepSurface = FALSE;
|
|
bAutomicCreate = FALSE;
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
|
|
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
// Hold the devlock throughout this process for
|
|
// the driver call and to protect heap manipulations.
|
|
|
|
EDD_SHAREDEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_DRIVER_ENABLED) &&
|
|
!(peDirectDrawGlobal->bSuspended))
|
|
{
|
|
// If the display pitch is 0 (which we should have already caught, but we want to
|
|
// be safe), fail the call now or else vDdCompleteSurfaceObject will blue screen.
|
|
|
|
if (peDirectDrawGlobal->HalInfo.vmiData.lDisplayPitch == 0)
|
|
{
|
|
CreateSurfaceData.ddRVal = DDERR_GENERIC;
|
|
}
|
|
else
|
|
{
|
|
// Secure all of the arrays that we are working with
|
|
|
|
hSecureSurfaceHandles = 0;
|
|
hSecureGlobals = 0;
|
|
hSecureLocals = 0;
|
|
hSecureMore = 0;
|
|
hSecureReturn = 0;
|
|
|
|
if (!BALLOC_OVERFLOW1(dwNumToCreate, HANDLE) &&
|
|
!BALLOC_OVERFLOW1(dwNumToCreate, DD_SURFACE_GLOBAL) &&
|
|
!BALLOC_OVERFLOW1(dwNumToCreate, DD_SURFACE_LOCAL) &&
|
|
!BALLOC_OVERFLOW1(dwNumToCreate, DD_SURFACE_MORE))
|
|
{
|
|
cjHandles = dwNumToCreate * sizeof(HANDLE);
|
|
cjGlobals = dwNumToCreate * sizeof(DD_SURFACE_GLOBAL);
|
|
cjLocals = dwNumToCreate * sizeof(DD_SURFACE_LOCAL);
|
|
cjMore = dwNumToCreate * sizeof(DD_SURFACE_MORE);
|
|
|
|
if (phSurfaceHandles &&
|
|
puSurfaceGlobalData &&
|
|
puSurfaceLocalData &&
|
|
puSurfaceMoreData &&
|
|
puhReturnSurfaceHandles)
|
|
{
|
|
__try
|
|
{
|
|
ProbeForWrite(phSurfaceHandles, cjHandles, sizeof(UCHAR));
|
|
hSecureSurfaceHandles = MmSecureVirtualMemory(phSurfaceHandles,
|
|
cjHandles,
|
|
PAGE_READWRITE);
|
|
|
|
ProbeForWrite(puSurfaceGlobalData, cjGlobals, sizeof(UCHAR));
|
|
hSecureGlobals = MmSecureVirtualMemory(puSurfaceGlobalData,
|
|
cjGlobals,
|
|
PAGE_READWRITE);
|
|
|
|
ProbeForWrite(puSurfaceLocalData, cjLocals, sizeof(UCHAR));
|
|
hSecureLocals = MmSecureVirtualMemory(puSurfaceLocalData,
|
|
cjLocals,
|
|
PAGE_READWRITE);
|
|
|
|
ProbeForWrite(puSurfaceMoreData, cjMore, sizeof(UCHAR));
|
|
hSecureMore = MmSecureVirtualMemory(puSurfaceMoreData,
|
|
cjMore,
|
|
PAGE_READWRITE);
|
|
|
|
ProbeForWrite(puhReturnSurfaceHandles, cjHandles, sizeof(UCHAR));
|
|
hSecureReturn = MmSecureVirtualMemory(puhReturnSurfaceHandles,
|
|
cjHandles,
|
|
PAGE_READWRITE);
|
|
RtlZeroMemory(puhReturnSurfaceHandles, cjHandles);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
// Allocate placeholder where we keep pointers to peSurface.
|
|
|
|
if (dwNumToCreate > 1)
|
|
{
|
|
peSurface = (EDD_SURFACE**) PALLOCMEM(sizeof(EDD_SURFACE*) * dwNumToCreate, 'pddG');
|
|
}
|
|
else
|
|
{
|
|
peSurface = &peSurfaceOnStack;
|
|
}
|
|
}
|
|
|
|
if ((hSecureSurfaceHandles != 0) &&
|
|
(hSecureGlobals != 0) &&
|
|
(hSecureLocals != 0) &&
|
|
(hSecureMore != 0) &&
|
|
(hSecureReturn != 0) &&
|
|
(peSurface != NULL))
|
|
{
|
|
// if driver supports atomic creation and we are creating more than 1 surface,
|
|
// allocate surface list.
|
|
|
|
if ((peDirectDrawGlobal->PrivateCaps.dwPrivateCaps & DDHAL_PRIVATECAP_ATOMICSURFACECREATION) &&
|
|
(dwNumToCreate > 1))
|
|
{
|
|
pSList = (DD_SURFACE_LOCAL**) PALLOCMEM(sizeof(DD_SURFACE_LOCAL*) * dwNumToCreate, 'pddG');
|
|
if (pSList != NULL)
|
|
{
|
|
bAutomicCreate = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pSList = NULL;
|
|
}
|
|
|
|
// Determine which function to call.
|
|
|
|
if (puSurfaceLocalData[0].ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER)
|
|
{
|
|
pfnCreate = peDirectDrawGlobal->D3dBufCallbacks.CreateD3DBuffer;
|
|
}
|
|
else
|
|
{
|
|
pfnCreate =
|
|
(peDirectDrawGlobal->CallBacks.dwFlags &
|
|
DDHAL_CB32_CREATESURFACE) ?
|
|
peDirectDrawGlobal->CallBacks.CreateSurface :
|
|
NULL;
|
|
}
|
|
|
|
CreateSurfaceData.ddRVal = DD_OK;
|
|
|
|
for (i = 0; (i < dwNumToCreate) && (CreateSurfaceData.ddRVal == DD_OK); i++)
|
|
{
|
|
// Do some basic parameter checking to avoid creating
|
|
// surfaces based on bad information.
|
|
|
|
if (!(puSurfaceLocalData[i].ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
bDdValidateSurfaceDescription(&puSurfaceGlobalData[i], &puSurfaceLocalData[i]))
|
|
{
|
|
peSurface[i] = peDdOpenNewSurfaceObject(peDirectDrawLocal,
|
|
phSurfaceHandles[i],
|
|
&puSurfaceGlobalData[i],
|
|
&puSurfaceLocalData[i],
|
|
&puSurfaceMoreData[i]);
|
|
if (peSurface[i] != NULL)
|
|
{
|
|
bKeepSurface = TRUE;
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
|
|
pSurfaceLocal = peSurface[i];
|
|
|
|
peSurface[i]->fpVidMem = 0;
|
|
peSurface[i]->fpHeapOffset = 0;
|
|
peSurface[i]->hCreatorProcess =
|
|
peDirectDrawLocal->UniqueProcess;
|
|
|
|
// Setup some internal flags that are required because some
|
|
// drivers look at them and not setting them for NT5 cause
|
|
// regressions in NT4 drivers and incompatibilites between
|
|
// Win9X driver code.
|
|
|
|
if ((SurfaceDescription.ddsCaps.dwCaps & DDSCAPS_OVERLAY) ||
|
|
((SurfaceDescription.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) &&
|
|
(peDirectDrawGlobal->HalInfo.ddCaps.dwCaps & DDCAPS_OVERLAY)))
|
|
{
|
|
peSurface[i]->dwFlags |= DDRAWISURF_HASOVERLAYDATA;
|
|
puSurfaceLocalData[i].dwFlags |= DDRAWISURF_HASOVERLAYDATA;
|
|
}
|
|
|
|
if (SurfaceDescription.dwFlags & DDSD_PIXELFORMAT)
|
|
{
|
|
if (!(SurfaceDescription.ddpfPixelFormat.dwFlags & DDPF_RGB) ||
|
|
(SurfaceDescription.ddpfPixelFormat.dwRGBBitCount !=
|
|
peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount) ||
|
|
((SurfaceDescription.ddpfPixelFormat.dwRGBBitCount != 8) &&
|
|
((SurfaceDescription.ddpfPixelFormat.dwRBitMask !=
|
|
peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRBitMask) ||
|
|
(SurfaceDescription.ddpfPixelFormat.dwGBitMask !=
|
|
peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwGBitMask) ||
|
|
(SurfaceDescription.ddpfPixelFormat.dwBBitMask !=
|
|
peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwBBitMask) ||
|
|
((SurfaceDescription.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) &&
|
|
(!(peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwFlags & DDPF_ALPHAPIXELS) ||
|
|
(SurfaceDescription.ddpfPixelFormat.dwRGBAlphaBitMask !=
|
|
peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBAlphaBitMask))))))
|
|
{
|
|
if (!(SurfaceDescription.ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
|
|
{
|
|
peSurface[i]->dwFlags |= DDRAWISURF_HASPIXELFORMAT;
|
|
puSurfaceLocalData[i].dwFlags |= DDRAWISURF_HASPIXELFORMAT;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If this is an automic create, we need to complete all of the surfaces
|
|
// only after the final create surface is called, otherwise we need to
|
|
// complete each surface as we go through the loop.
|
|
|
|
if (bAutomicCreate)
|
|
{
|
|
dwStart = 0;
|
|
|
|
if (i == (dwNumToCreate - 1))
|
|
{
|
|
dwEnd = dwNumToCreate;
|
|
}
|
|
else
|
|
{
|
|
dwEnd = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwStart = i;
|
|
dwEnd = i + 1;
|
|
}
|
|
|
|
// Primary surfaces aren't truly allocated, so
|
|
// intercept requests for primary allocations and
|
|
// trivially succeed them with recorded primary information.
|
|
|
|
bNotifyCreation = TRUE;
|
|
|
|
if (peSurface[i]->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
|
|
{
|
|
peSurface[i]->fpVidMem =
|
|
peDirectDrawGlobal->HalInfo.vmiData.fpPrimary;
|
|
peSurface[i]->lPitch =
|
|
peDirectDrawGlobal->HalInfo.vmiData.lDisplayPitch;
|
|
peSurface[i]->wWidth =
|
|
peDirectDrawGlobal->HalInfo.vmiData.dwDisplayWidth;
|
|
peSurface[i]->wHeight =
|
|
peDirectDrawGlobal->HalInfo.vmiData.dwDisplayHeight;
|
|
peSurface[i]->ddpfSurface =
|
|
peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay;
|
|
|
|
peSurface[i]->fl |= DD_SURFACE_FLAG_PRIMARY;
|
|
|
|
CreateSurfaceData.ddRVal = DD_OK;
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
|
|
if (!(peDirectDrawGlobal->PrivateCaps.dwPrivateCaps & DDHAL_PRIVATECAP_NOTIFYPRIMARYCREATION))
|
|
{
|
|
bNotifyCreation = FALSE;
|
|
}
|
|
|
|
DDKHEAP(("DDKHEAP: Allocated primary %X, surf %X (%X)\n",
|
|
peSurface[i]->fpVidMem, peSurface[i]->hGet(),
|
|
peSurface[i]));
|
|
}
|
|
|
|
if (dwStart != dwEnd)
|
|
{
|
|
// Determines whether the memory type was explicit or not, so we know
|
|
// if we can change it if an allocation fails later.
|
|
|
|
if (dwForceMemType == 0)
|
|
{
|
|
bAnyType = !(peSurface[dwStart]->ddsCaps.dwCaps &
|
|
(DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM));
|
|
|
|
// if it's not any type, initialize force mem type so that always
|
|
// that type for all surfaces.
|
|
|
|
if (!bAnyType)
|
|
{
|
|
dwForceMemType = peSurface[dwStart]->ddsCaps.dwCaps &
|
|
(DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM);
|
|
}
|
|
}
|
|
|
|
// if force allocations, set the same memory type as the first one
|
|
|
|
if (dwForceMemType)
|
|
{
|
|
for (j = dwStart; j < dwEnd; j++)
|
|
{
|
|
peSurface[j]->ddsCaps.dwCaps &=
|
|
~(DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM);
|
|
peSurface[j]->ddsCaps.dwCaps |= dwForceMemType;
|
|
}
|
|
}
|
|
|
|
if ((pfnCreate != NULL) && bNotifyCreation)
|
|
{
|
|
// Let the driver attempt to allocate the surface first.
|
|
|
|
CreateSurfaceData.lpDD = peDirectDrawGlobal;
|
|
CreateSurfaceData.lpDDSurfaceDesc = (DDSURFACEDESC*)&SurfaceDescription;
|
|
|
|
if (bAutomicCreate)
|
|
{
|
|
for (j = dwStart; j < dwEnd; j++)
|
|
{
|
|
pSList[j] = peSurface[j];
|
|
}
|
|
|
|
CreateSurfaceData.lplpSList = pSList;
|
|
CreateSurfaceData.dwSCnt = dwNumToCreate;
|
|
}
|
|
else
|
|
{
|
|
CreateSurfaceData.lplpSList = &pSurfaceLocal;
|
|
CreateSurfaceData.dwSCnt = 1;
|
|
}
|
|
|
|
dwRet = pfnCreate(&CreateSurfaceData);
|
|
|
|
if (dwRet == DDHAL_DRIVER_HANDLED)
|
|
{
|
|
if (CreateSurfaceData.ddRVal == DD_OK)
|
|
{
|
|
for (j = dwStart; j < dwEnd; j++)
|
|
{
|
|
// Set the driver created flag because the driver
|
|
// involved itself in the creation.
|
|
|
|
peSurface[j]->fl |=
|
|
DD_SURFACE_FLAG_DRIVER_CREATED;
|
|
}
|
|
|
|
for (j = dwStart;
|
|
(j < dwEnd) && (CreateSurfaceData.ddRVal == DD_OK);
|
|
j++)
|
|
{
|
|
// If the surfaces were allocated from one of our non-local
|
|
// heaps, commit sufficient virtual memory and fill in the
|
|
// virtual address for fpVidMem so the surface can be locked
|
|
// and accessed by user mode apps:
|
|
|
|
if ((peSurface[j]->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM) &&
|
|
(peSurface[j]->lpVidMemHeap != NULL) &&
|
|
(peSurface[j]->lpVidMemHeap->lpHeap != NULL) &&
|
|
!(peSurface[j]->lpVidMemHeap->dwFlags & VIDMEM_ISHEAP) &&
|
|
(peSurface[j]->lpVidMemHeap->dwFlags & VIDMEM_ISNONLOCAL))
|
|
{
|
|
CreateSurfaceData.ddRVal =
|
|
hrDdCommitAgpSurface(peSurface[j], 0);
|
|
}
|
|
}
|
|
|
|
if (CreateSurfaceData.ddRVal == DD_OK)
|
|
{
|
|
if (dwForceMemType == 0)
|
|
{
|
|
// All surfaces must be of the same type as the first
|
|
// so we remember the type of surface type which
|
|
// we have successfully created.
|
|
|
|
// This only has meaning non-atomic case, since
|
|
// if driver can do atomic creation and handled it
|
|
// without error, that's driver's responsibility to
|
|
// make sure all surface came from same type of memory.
|
|
|
|
dwForceMemType =
|
|
peSurface[dwStart]->ddsCaps.dwCaps &
|
|
(DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM);
|
|
}
|
|
}
|
|
}
|
|
|
|
DDKHEAP(("DDHKEAP: Driver alloced %X, "
|
|
"hr %X, surf %X (%X)\n",
|
|
peSurface[i]->fpVidMem,
|
|
CreateSurfaceData.ddRVal,
|
|
peSurface[i]->hGet(),
|
|
peSurface[i]));
|
|
}
|
|
else if (peSurface[dwStart]->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
|
|
{
|
|
// Driver possible to return NOTHANDLED for notification of
|
|
// primary surface cration, but creation itself is done by
|
|
// us in above, but we had "notified" to driver, make
|
|
// the surface as driver created. (so that we call driver
|
|
// when destroy).
|
|
|
|
peSurface[dwStart]->fl |=
|
|
DD_SURFACE_FLAG_DRIVER_CREATED;
|
|
}
|
|
}
|
|
|
|
if (dwRet == DDHAL_DRIVER_NOTHANDLED)
|
|
{
|
|
// FIX WINBUG: #322363
|
|
// Prevent setup blue-screen playing intro AVI on nv3 display drivers
|
|
|
|
if ((SurfaceDescription.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) &&
|
|
(SurfaceDescription.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
|
|
{
|
|
// Mask off system memory flag
|
|
WARNING("Driver turn on SYSTEMMEMORY flag, disable it");
|
|
SurfaceDescription.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY;
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
|
|
for (j = dwStart;
|
|
(j < dwEnd) && (CreateSurfaceData.ddRVal == DD_OK);
|
|
j++)
|
|
{
|
|
if (peSurface[j]->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
|
|
{
|
|
// Driver possible to return NOTHANDLED for notification of
|
|
// primary surface cration, but creation itself is done by
|
|
// us in above, so just ignore driver return.
|
|
// Since this is just "notification" to driver, we don't
|
|
// except any work in driver basically.
|
|
|
|
CreateSurfaceData.ddRVal = DD_OK;
|
|
}
|
|
else
|
|
{
|
|
// FIX WINBUG: #322363
|
|
// Prevent setup blue-screen playing intro AVI on nv3 display drivers
|
|
|
|
if ((peSurface[j]->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) &&
|
|
(peSurface[j]->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
|
|
{
|
|
// Mask off system memory flag
|
|
WARNING("Driver turn on SYSTEMMEMORY flag, disable it");
|
|
peSurface[j]->ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY;
|
|
}
|
|
|
|
if (peSurface[j]->fpVidMem != DDHAL_PLEASEALLOC_USERMEM)
|
|
{
|
|
// Force allocations to the same memory type as the first
|
|
|
|
if (dwForceMemType)
|
|
{
|
|
peSurface[j]->ddsCaps.dwCaps &=
|
|
~(DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM);
|
|
peSurface[j]->ddsCaps.dwCaps |= dwForceMemType;
|
|
}
|
|
|
|
// The driver didn't allocate a vidmem surface, so try
|
|
// to allocate one from system-managed memory.
|
|
|
|
CreateSurfaceData.ddRVal =
|
|
hrDdAllocSurface(peDirectDrawLocal,
|
|
peDirectDrawGlobal,
|
|
peSurface[j]);
|
|
|
|
DDKHEAP(("DDHKEAP: Heap alloced %X, "
|
|
"hr %X, surf %X (%X)\n",
|
|
peSurface[j]->fpVidMem,
|
|
CreateSurfaceData.ddRVal,
|
|
peSurface[j]->hGet(),
|
|
peSurface[j]));
|
|
|
|
if (CreateSurfaceData.ddRVal == DD_OK)
|
|
{
|
|
if (dwForceMemType == 0)
|
|
{
|
|
// All surfaces must be of the same type as the first
|
|
// so we remember the type of surface type which
|
|
// we have successfully created first time.
|
|
|
|
dwForceMemType =
|
|
peSurface[j]->ddsCaps.dwCaps &
|
|
(DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No forcemem things for user mode memory allocation.
|
|
//
|
|
// The driver didn't allocate a vidmem surface, so try
|
|
// to allocate one from system-managed memory.
|
|
|
|
CreateSurfaceData.ddRVal =
|
|
hrDdAllocSurface(peDirectDrawLocal,
|
|
peDirectDrawGlobal,
|
|
peSurface[j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// An attempt to allocate was made either by the driver
|
|
// or by the system allocator. If the attempt succeeded,
|
|
// complete the surface creation.
|
|
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(CreateSurfaceData.ddRVal == DD_OK))
|
|
{
|
|
// The object is complete. We can ignore any
|
|
// following DxDdCreateSurfaceObject calls that may
|
|
// occur on this object.
|
|
|
|
for (j = dwStart; j < dwEnd; j++)
|
|
{
|
|
vDdCompleteSurfaceObject(peDirectDrawLocal, peSurface[j]);
|
|
|
|
#if 0
|
|
ASSERTGDI((peSurface[j]->fl & DD_SURFACE_FLAG_PRIMARY) ||
|
|
(peSurface[j]->fpVidMem !=
|
|
peDirectDrawGlobal->HalInfo.vmiData.fpPrimary),
|
|
"Expected primary surface to be marked as such");
|
|
#endif
|
|
ASSERTGDI(peSurface[j]->hbmGdi == NULL,
|
|
"DxDdCreateSurface: Invalid cached bitmap");
|
|
|
|
if (peSurface[j]->bLost)
|
|
{
|
|
// Surface is ready for use.
|
|
peSurface[j]->bLost = FALSE;
|
|
|
|
// Now this surface is ready to go, increment active surface ref. count.
|
|
peSurface[j]->peDirectDrawLocal->cActiveSurface++;
|
|
|
|
ASSERTGDI(peSurface[j]->peDirectDrawLocal->cActiveSurface <=
|
|
peSurface[j]->peDirectDrawLocal->cSurface,
|
|
"cActiveSurface is > than cSurface");
|
|
}
|
|
|
|
// Copy surface information to local storage
|
|
// for access after the unlock.
|
|
|
|
puSurfaceGlobalData[j] = *peSurface[j];
|
|
puSurfaceLocalData[j].ddsCaps = peSurface[j]->ddsCaps;
|
|
puSurfaceMoreData[j].ddsCapsEx = peSurface[j]->ddsCapsEx;
|
|
|
|
// We were successful, so unlock the surface:
|
|
|
|
puhReturnSurfaceHandles[j] = peSurface[j]->hGet();
|
|
}
|
|
}
|
|
|
|
} // if (dwStart != dwEnd)
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdCreateSurface: Couldn't allocate surface\n");
|
|
CreateSurfaceData.ddRVal = DDERR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdCreateSurface: Bad surface description\n");
|
|
CreateSurfaceData.ddRVal = DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
} // For loop
|
|
|
|
// The surface object is now created, call CreateSurfaceEx, to
|
|
// inform the driver to associate a cookie if the driver can
|
|
|
|
if ((peDirectDrawGlobal->Miscellaneous2CallBacks.CreateSurfaceEx)
|
|
&& (CreateSurfaceData.ddRVal == DD_OK)
|
|
&& (NULL != peSurface[0])
|
|
&& (0 != peSurface[0]->dwSurfaceHandle)
|
|
)
|
|
{
|
|
DD_CREATESURFACEEXDATA CreateSurfaceExData;
|
|
CreateSurfaceExData.ddRVal = DDERR_GENERIC;
|
|
CreateSurfaceExData.dwFlags = 0;
|
|
CreateSurfaceExData.lpDDLcl = peDirectDrawLocal;
|
|
CreateSurfaceExData.lpDDSLcl = peSurface[0];
|
|
|
|
dwRet = peDirectDrawGlobal->Miscellaneous2CallBacks.CreateSurfaceEx(&CreateSurfaceExData);
|
|
if (dwRet != DDHAL_DRIVER_HANDLED)
|
|
{
|
|
// For now, simply warn that the driver failed to associate the surface with the
|
|
// token and continue
|
|
WARNING("dwDdCreateSurfaceOrBuffer: DDI call to the driver not handled\n");
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
CreateSurfaceData.ddRVal = DDERR_GENERIC;
|
|
}
|
|
else
|
|
{
|
|
// need to prop the return value as if it's in CreateSurfaceData
|
|
CreateSurfaceData.ddRVal = CreateSurfaceExData.ddRVal;
|
|
}
|
|
}
|
|
|
|
// Unlock the surfaces and clean up any failures.
|
|
|
|
for (j = 0; j < i; j++)
|
|
{
|
|
if (peSurface[j] != NULL)
|
|
{
|
|
if (CreateSurfaceData.ddRVal != DD_OK)
|
|
{
|
|
// Failure, so clean up the surface object.
|
|
bDdDeleteSurfaceObject(peSurface[j]->hGet(), NULL);
|
|
|
|
// bKeepSurface is left at TRUE so that any
|
|
// failure codes get written back. Ensure
|
|
// that fpVidMem is zero on return.
|
|
puSurfaceGlobalData[j].fpVidMem = 0;
|
|
puhReturnSurfaceHandles[j] = 0;
|
|
}
|
|
else
|
|
{
|
|
DEC_EXCLUSIVE_REF_CNT(peSurface[j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdCreateSurface: Unable to allocate or secure memory\n");
|
|
}
|
|
|
|
if (hSecureSurfaceHandles)
|
|
{
|
|
MmUnsecureVirtualMemory(hSecureSurfaceHandles);
|
|
}
|
|
if (hSecureGlobals)
|
|
{
|
|
MmUnsecureVirtualMemory(hSecureGlobals);
|
|
}
|
|
if (hSecureLocals)
|
|
{
|
|
MmUnsecureVirtualMemory(hSecureLocals);
|
|
}
|
|
if (hSecureMore)
|
|
{
|
|
MmUnsecureVirtualMemory(hSecureMore);
|
|
}
|
|
if (hSecureReturn)
|
|
{
|
|
MmUnsecureVirtualMemory(hSecureReturn);
|
|
}
|
|
if (peSurface != &peSurfaceOnStack)
|
|
{
|
|
VFREEMEM(peSurface);
|
|
}
|
|
if (pSList != NULL)
|
|
{
|
|
VFREEMEM(pSList);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_DRIVER_ENABLED))
|
|
{
|
|
WARNING("DxDdCreateSurface: Driver doesn't support this mode\n");
|
|
}
|
|
else
|
|
{
|
|
CreateSurfaceData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdCreateSurface: Invalid object\n");
|
|
}
|
|
|
|
DDKHEAP(("DDKHEAP: Create returns %X, rval %X\n",
|
|
dwRet, CreateSurfaceData.ddRVal));
|
|
|
|
// We have to wrap this in another try-except because the user-mode
|
|
// memory containing the input may have been deallocated by now:
|
|
|
|
__try
|
|
{
|
|
if (dwRet == DDHAL_DRIVER_HANDLED)
|
|
{
|
|
ProbeAndWriteRVal(&puCreateSurfaceData->ddRVal,
|
|
CreateSurfaceData.ddRVal);
|
|
}
|
|
|
|
if (bKeepSurface)
|
|
{
|
|
ProbeAndWriteStructure((DDSURFACEDESC2*)puSurfaceDescription,
|
|
SurfaceDescription,
|
|
DDSURFACEDESC2);
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdCreateSurface
|
|
*
|
|
* Corresponds to HAL CreateSurface entry point.
|
|
*
|
|
* Calls the driver to create a DirectDraw surface.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdCreateSurface(
|
|
HANDLE hDirectDraw,
|
|
HANDLE* puhSurfaceHandle,
|
|
DDSURFACEDESC* puSurfaceDescription,
|
|
DD_SURFACE_GLOBAL* puSurfaceGlobalData,
|
|
DD_SURFACE_LOCAL* puSurfaceLocalData,
|
|
DD_SURFACE_MORE* puSurfaceMoreData,
|
|
DD_CREATESURFACEDATA* puCreateSurfaceData,
|
|
HANDLE* puhSurface
|
|
)
|
|
{
|
|
return dwDdCreateSurfaceOrBuffer(hDirectDraw, puhSurfaceHandle,
|
|
puSurfaceDescription, puSurfaceGlobalData,
|
|
puSurfaceLocalData, puSurfaceMoreData,
|
|
puCreateSurfaceData, puhSurface);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdDestroySurface
|
|
*
|
|
* Calls the driver to delete a surface it created via CreateSurface.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdDestroySurface(
|
|
HANDLE hSurface,
|
|
BOOL bRealDestroy
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_SURFACE* peSurface;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
BOOL b;
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if (peSurface != NULL)
|
|
{
|
|
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
|
|
|
|
{
|
|
EDD_SHAREDEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if(bRealDestroy)
|
|
{
|
|
vDdDisableSurfaceObject(peDirectDrawGlobal,
|
|
peSurface,
|
|
&dwRet);
|
|
}
|
|
else
|
|
{
|
|
vDdLooseManagedSurfaceObject(peDirectDrawGlobal,
|
|
peSurface,
|
|
&dwRet);
|
|
return(dwRet);
|
|
}
|
|
}
|
|
|
|
// vDdDisableSurfaceObject doesn't delete the DC because it may
|
|
// be called from a different process than the one that created
|
|
// the DC. However, at this point we're guaranteed to be in the
|
|
// process that created the DC, so we should delete it now:
|
|
|
|
if (peSurface->hdc)
|
|
{
|
|
b = DxEngDeleteDC(peSurface->hdc, TRUE);
|
|
|
|
// DC may still be in use, which would cause the delete to fail,
|
|
// so we don't assert on the return value (the DC will still get
|
|
// cleaned up at process termination):
|
|
|
|
if (!b)
|
|
{
|
|
WARNING("DxDdDestroySurface: bDeleteDCInternal failed");
|
|
}
|
|
|
|
peSurface->hdc = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdDestroySurface: Couldn't lock DirectDraw surface");
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdCreateD3DBuffer
|
|
*
|
|
* Calls the driver to create a D3D buffer.
|
|
*
|
|
* Corresponds to HAL CreateD3DBuffer entry point.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdCreateD3DBuffer(
|
|
HANDLE hDirectDraw,
|
|
HANDLE* puhSurfaceHandle,
|
|
DDSURFACEDESC* puSurfaceDescription,
|
|
DD_SURFACE_GLOBAL* puSurfaceGlobalData,
|
|
DD_SURFACE_LOCAL* puSurfaceLocalData,
|
|
DD_SURFACE_MORE* puSurfaceMoreData,
|
|
DD_CREATESURFACEDATA* puCreateSurfaceData,
|
|
HANDLE* puhSurface
|
|
)
|
|
{
|
|
return dwDdCreateSurfaceOrBuffer(hDirectDraw, puhSurfaceHandle,
|
|
puSurfaceDescription, puSurfaceGlobalData,
|
|
puSurfaceLocalData, puSurfaceMoreData,
|
|
puCreateSurfaceData, puhSurface);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdDestroyD3DBuffer
|
|
*
|
|
* Calls the driver to delete a surface it created via CreateD3DBuffer.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdDestroyD3DBuffer(
|
|
HANDLE hSurface
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_SURFACE* peSurface;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if (peSurface != NULL)
|
|
{
|
|
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
|
|
|
|
{
|
|
EDD_SHAREDEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
vDdDisableSurfaceObject(peDirectDrawGlobal,
|
|
peSurface,
|
|
&dwRet);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdDestroyD3DBuffer: Couldn't lock DirectDraw surface");
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdSetColorKey
|
|
*
|
|
* This entry point is always hooked by NT kernel, regardless of whether
|
|
* the driver hooks it or not.
|
|
*
|
|
* Note that this call does not necessary need to be called on an overlay
|
|
* surface.
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdSetColorKey(
|
|
HANDLE hSurface,
|
|
PDD_SETCOLORKEYDATA puSetColorKeyData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_SETCOLORKEYDATA SetColorKeyData;
|
|
|
|
__try
|
|
{
|
|
SetColorKeyData = ProbeAndReadStructure(puSetColorKeyData,
|
|
DD_SETCOLORKEYDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
SetColorKeyData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_SURFACE* peSurface;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if ((peSurface != NULL) &&
|
|
!(peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
|
|
{
|
|
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
|
|
|
|
if (SetColorKeyData.dwFlags & DDCKEY_SRCBLT)
|
|
{
|
|
peSurface->dwFlags |= DDRAWISURF_HASCKEYSRCBLT;
|
|
peSurface->ddckCKSrcBlt = SetColorKeyData.ckNew;
|
|
}
|
|
|
|
// If the driver doesn't hook SetColorKey, we return
|
|
// DDHAL_DRIVER_NOTHANDLED, which means okay.
|
|
|
|
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags &
|
|
DDHAL_SURFCB32_SETCOLORKEY)
|
|
{
|
|
SetColorKeyData.lpDD = peDirectDrawGlobal;
|
|
SetColorKeyData.lpDDSurface = peSurface;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (peSurface->bLost)
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
SetColorKeyData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
SurfaceCallBacks.SetColorKey(&SetColorKeyData);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdSetColorKey: Invalid surface or dwFlags\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(&puSetColorKeyData->ddRVal, SetColorKeyData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdAddAttachedSurface
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdAddAttachedSurface(
|
|
HANDLE hSurface,
|
|
HANDLE hSurfaceAttached,
|
|
PDD_ADDATTACHEDSURFACEDATA puAddAttachedSurfaceData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_ADDATTACHEDSURFACEDATA AddAttachedSurfaceData;
|
|
|
|
__try
|
|
{
|
|
AddAttachedSurfaceData = ProbeAndReadStructure(puAddAttachedSurfaceData,
|
|
DD_ADDATTACHEDSURFACEDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
AddAttachedSurfaceData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_SURFACE* peSurface;
|
|
EDD_SURFACE* peSurfaceAttached;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_LOCK_SURFACE eLockSurfaceAttached;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
peSurfaceAttached = eLockSurfaceAttached.peLock(hSurfaceAttached);
|
|
if ((peSurface != NULL) &&
|
|
(peSurfaceAttached != NULL) &&
|
|
!(peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
!(peSurfaceAttached->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
(peSurface->peDirectDrawLocal == peSurfaceAttached->peDirectDrawLocal))
|
|
{
|
|
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
|
|
|
|
// If the driver doesn't hook AddAttachedSurface, we return
|
|
// DDHAL_DRIVER_NOTHANDLED, which means okay.
|
|
|
|
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags &
|
|
DDHAL_SURFCB32_ADDATTACHEDSURFACE)
|
|
{
|
|
AddAttachedSurfaceData.lpDD = peDirectDrawGlobal;
|
|
AddAttachedSurfaceData.lpDDSurface = peSurface;
|
|
AddAttachedSurfaceData.lpSurfAttached = peSurfaceAttached;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((peSurface->bLost) || (peSurfaceAttached->bLost))
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
AddAttachedSurfaceData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
SurfaceCallBacks.AddAttachedSurface(&AddAttachedSurfaceData);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdAddAttachedSurface: Invalid surface or dwFlags\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(&puAddAttachedSurfaceData->ddRVal,
|
|
AddAttachedSurfaceData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdUpdateOverlay
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdUpdateOverlay(
|
|
HANDLE hSurfaceDestination,
|
|
HANDLE hSurfaceSource,
|
|
PDD_UPDATEOVERLAYDATA puUpdateOverlayData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_UPDATEOVERLAYDATA UpdateOverlayData;
|
|
EDD_VIDEOPORT* peVideoPort = NULL;
|
|
EDD_DXSURFACE* peDxSurface;
|
|
DWORD dwOldFlags;
|
|
|
|
__try
|
|
{
|
|
UpdateOverlayData = ProbeAndReadStructure(puUpdateOverlayData,
|
|
DD_UPDATEOVERLAYDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
UpdateOverlayData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_SURFACE* peSurfaceSource;
|
|
EDD_SURFACE* peSurfaceDestination;
|
|
EDD_SURFACE* peSurface;
|
|
EDD_LOCK_SURFACE eLockSurfaceSource;
|
|
EDD_LOCK_SURFACE eLockSurfaceDestination;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
// 'peSurfaceSource' is the overlay surface, 'peSurfaceDestination' is
|
|
// the surface to be overlayed.
|
|
|
|
peSurfaceSource = eLockSurfaceSource.peLock(hSurfaceSource);
|
|
if ((peSurfaceSource != NULL) &&
|
|
!(peSurfaceSource->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
(peSurfaceSource->ddsCaps.dwCaps & DDSCAPS_OVERLAY))
|
|
{
|
|
peDirectDrawGlobal = peSurfaceSource->peDirectDrawGlobal;
|
|
|
|
// If we're being asked to hide the overlay, then we don't need
|
|
// check any more parameters:
|
|
|
|
peSurfaceDestination = NULL;
|
|
if (!(UpdateOverlayData.dwFlags & DDOVER_HIDE))
|
|
{
|
|
// Okay, we have to validate every parameter in this call:
|
|
|
|
peSurfaceDestination
|
|
= eLockSurfaceDestination.peLock(hSurfaceDestination);
|
|
|
|
if ((peSurfaceDestination == NULL) ||
|
|
(peSurfaceDestination->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) ||
|
|
(peSurfaceDestination->peDirectDrawLocal !=
|
|
peSurfaceSource->peDirectDrawLocal) ||
|
|
(UpdateOverlayData.rDest.left < DD_MINIMUM_COORDINATE) ||
|
|
(UpdateOverlayData.rDest.top < DD_MINIMUM_COORDINATE) ||
|
|
(UpdateOverlayData.rDest.right > DD_MAXIMUM_COORDINATE) ||
|
|
(UpdateOverlayData.rDest.bottom > DD_MAXIMUM_COORDINATE) ||
|
|
(UpdateOverlayData.rDest.left >= UpdateOverlayData.rDest.right) ||
|
|
(UpdateOverlayData.rDest.top >= UpdateOverlayData.rDest.bottom) ||
|
|
(UpdateOverlayData.rSrc.left < DD_MINIMUM_COORDINATE) ||
|
|
(UpdateOverlayData.rSrc.top < DD_MINIMUM_COORDINATE) ||
|
|
(UpdateOverlayData.rSrc.right > DD_MAXIMUM_COORDINATE) ||
|
|
(UpdateOverlayData.rSrc.bottom > DD_MAXIMUM_COORDINATE) ||
|
|
(UpdateOverlayData.rSrc.left >= UpdateOverlayData.rSrc.right) ||
|
|
(UpdateOverlayData.rSrc.top >= UpdateOverlayData.rSrc.bottom))
|
|
{
|
|
WARNING("DxDdUpdateOverlay: Invalid destination or rectangle\n");
|
|
return(dwRet);
|
|
}
|
|
|
|
// We don't keep track of pSurfaceLocal->ddckCKSrcOverlay in
|
|
// kernel mode, so we always expect the user-mode call to convert
|
|
// to DDOVER_KEYDESTOVERRIDE or DDOVER_KEYSRCOVERRIDE. It is by
|
|
// no means fatal if this is not the case, so we only do a warning:
|
|
|
|
if ((UpdateOverlayData.dwFlags & DDOVER_KEYDEST) ||
|
|
(UpdateOverlayData.dwFlags & DDOVER_KEYSRC))
|
|
{
|
|
WARNING("DxDdUpdateOverlay: Expected user-mode to set OVERRIDE\n");
|
|
}
|
|
|
|
// If using a video port, disable autoflipping and hardware
|
|
// bob when neccesary
|
|
|
|
if( peSurfaceSource->ddsCaps.dwCaps & DDSCAPS_VIDEOPORT )
|
|
{
|
|
peVideoPort = (EDD_VIDEOPORT*) peSurfaceSource->lpVideoPort;
|
|
if( peVideoPort != NULL )
|
|
{
|
|
if( ( peVideoPort->peDxVideoPort->bSoftwareAutoflip ) ||
|
|
( peVideoPort->peDxVideoPort->flFlags & DD_DXVIDEOPORT_FLAG_SOFTWAREBOB ) )
|
|
{
|
|
UpdateOverlayData.dwFlags &= ~(DDOVER_AUTOFLIP|DDOVER_BOBHARDWARE);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If this surface is being used by DxApi, change to weave if
|
|
// DxApi told it to and visa versa.
|
|
|
|
peDxSurface = peSurfaceSource->peDxSurface;
|
|
if( peDxSurface != NULL )
|
|
{
|
|
if( peDxSurface->flFlags & DD_DXSURFACE_FLAG_STATE_SET )
|
|
{
|
|
if( peDxSurface->flFlags & DD_DXSURFACE_FLAG_STATE_BOB )
|
|
{
|
|
UpdateOverlayData.dwFlags |= DDOVER_BOB;
|
|
}
|
|
else if( peDxSurface->flFlags & DD_DXSURFACE_FLAG_STATE_WEAVE )
|
|
{
|
|
UpdateOverlayData.dwFlags &= ~DDOVER_BOB | DDOVER_BOBHARDWARE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags
|
|
& DDHAL_SURFCB32_UPDATEOVERLAY)
|
|
{
|
|
UpdateOverlayData.lpDD = peDirectDrawGlobal;
|
|
UpdateOverlayData.lpDDDestSurface = peSurfaceDestination;
|
|
UpdateOverlayData.lpDDSrcSurface = peSurfaceSource;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((peSurfaceSource->bLost) ||
|
|
((peSurfaceDestination != NULL) && (peSurfaceDestination->bLost)))
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
UpdateOverlayData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else
|
|
{
|
|
peSurfaceSource->fl |= DD_SURFACE_FLAG_UPDATE_OVERLAY_CALLED;
|
|
|
|
dwRet = peDirectDrawGlobal->SurfaceCallBacks.UpdateOverlay(
|
|
&UpdateOverlayData);
|
|
|
|
// If it failed due to hardware autoflipping/bobbing
|
|
// and software autoflipping is an option, try again
|
|
// without hardware autolfipping. If it works, we will
|
|
// revert to software autoflipping.
|
|
|
|
if( ( dwRet == DDHAL_DRIVER_HANDLED ) &&
|
|
( UpdateOverlayData.ddRVal != DD_OK ) &&
|
|
( UpdateOverlayData.dwFlags & (DDOVER_AUTOFLIP|DDOVER_BOBHARDWARE) ) &&
|
|
( peDirectDrawGlobal->DDKernelCaps.dwCaps & DDKERNELCAPS_AUTOFLIP ) )
|
|
{
|
|
dwOldFlags = UpdateOverlayData.dwFlags;
|
|
UpdateOverlayData.dwFlags &= ~(DDOVER_AUTOFLIP|DDOVER_BOBHARDWARE);
|
|
dwRet = peDirectDrawGlobal->SurfaceCallBacks.UpdateOverlay(
|
|
&UpdateOverlayData);
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(UpdateOverlayData.ddRVal == DD_OK))
|
|
{
|
|
if( dwOldFlags & DDOVER_AUTOFLIP )
|
|
{
|
|
peVideoPort->peDxVideoPort->bSoftwareAutoflip = TRUE;
|
|
if( peVideoPort->cAutoflipVideo > 0 )
|
|
{
|
|
peVideoPort->peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_AUTOFLIP;
|
|
}
|
|
if( peVideoPort->cAutoflipVbi > 0 )
|
|
{
|
|
peVideoPort->peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_AUTOFLIP_VBI;
|
|
}
|
|
}
|
|
if( dwOldFlags & DDOVER_BOBHARDWARE )
|
|
{
|
|
peVideoPort->peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_SOFTWAREBOB;
|
|
}
|
|
}
|
|
}
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(UpdateOverlayData.ddRVal == DD_OK))
|
|
{
|
|
// Update the DXAPI data for all surfaces in the chain:
|
|
|
|
if( peVideoPort != NULL )
|
|
{
|
|
if( UpdateOverlayData.dwFlags & DDOVER_BOB )
|
|
{
|
|
peVideoPort->peDxVideoPort->flFlags |= DD_DXVIDEOPORT_FLAG_BOB;
|
|
}
|
|
else
|
|
{
|
|
peVideoPort->peDxVideoPort->flFlags &= ~DD_DXVIDEOPORT_FLAG_BOB;
|
|
}
|
|
}
|
|
peSurface = peSurfaceSource;
|
|
while (TRUE)
|
|
{
|
|
peSurface->dwOverlayFlags = UpdateOverlayData.dwFlags;
|
|
|
|
peSurface->dwOverlaySrcWidth
|
|
= UpdateOverlayData.rSrc.right -
|
|
UpdateOverlayData.rSrc.left;
|
|
peSurface->dwOverlaySrcHeight
|
|
= UpdateOverlayData.rSrc.bottom -
|
|
UpdateOverlayData.rSrc.top;
|
|
peSurface->dwOverlayDestWidth
|
|
= UpdateOverlayData.rDest.right -
|
|
UpdateOverlayData.rDest.left;
|
|
peSurface->dwOverlayDestHeight
|
|
= UpdateOverlayData.rDest.bottom -
|
|
UpdateOverlayData.rDest.top;
|
|
|
|
peSurface->rcOverlaySrc.left =
|
|
UpdateOverlayData.rSrc.left;
|
|
peSurface->rcOverlaySrc.right =
|
|
UpdateOverlayData.rSrc.right;
|
|
peSurface->rcOverlaySrc.top =
|
|
UpdateOverlayData.rSrc.top;
|
|
peSurface->rcOverlaySrc.bottom =
|
|
UpdateOverlayData.rSrc.bottom;
|
|
|
|
vDdSynchronizeSurface(peSurface);
|
|
|
|
if (peSurface->lpAttachList == NULL)
|
|
break;
|
|
|
|
peSurface
|
|
= pedFromLp(peSurface->lpAttachList->lpAttached);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdUpdateOverlay: Invalid source or dwFlags\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(&puUpdateOverlayData->ddRVal, UpdateOverlayData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdSetOverlayPosition
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdSetOverlayPosition(
|
|
HANDLE hSurfaceSource,
|
|
HANDLE hSurfaceDestination,
|
|
PDD_SETOVERLAYPOSITIONDATA puSetOverlayPositionData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_SETOVERLAYPOSITIONDATA SetOverlayPositionData;
|
|
|
|
__try
|
|
{
|
|
SetOverlayPositionData = ProbeAndReadStructure(puSetOverlayPositionData,
|
|
DD_SETOVERLAYPOSITIONDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
SetOverlayPositionData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_SURFACE* peSurfaceSource;
|
|
EDD_SURFACE* peSurfaceDestination;
|
|
EDD_LOCK_SURFACE eLockSurfaceSource;
|
|
EDD_LOCK_SURFACE eLockSurfaceDestination;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peSurfaceSource = eLockSurfaceSource.peLock(hSurfaceSource);
|
|
peSurfaceDestination = eLockSurfaceSource.peLock(hSurfaceDestination);
|
|
if ((peSurfaceSource != NULL) &&
|
|
(peSurfaceDestination != NULL) &&
|
|
(peSurfaceSource->ddsCaps.dwCaps & DDSCAPS_OVERLAY) &&
|
|
!(peSurfaceSource->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
!(peSurfaceDestination->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
|
|
{
|
|
peDirectDrawGlobal = peSurfaceSource->peDirectDrawGlobal;
|
|
|
|
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags &
|
|
DDHAL_SURFCB32_SETOVERLAYPOSITION)
|
|
{
|
|
SetOverlayPositionData.lpDD = peDirectDrawGlobal;
|
|
SetOverlayPositionData.lpDDSrcSurface = peSurfaceSource;
|
|
SetOverlayPositionData.lpDDDestSurface = peSurfaceDestination;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((peSurfaceSource->bLost) || (peSurfaceDestination->bLost))
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
SetOverlayPositionData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
SurfaceCallBacks.SetOverlayPosition(&SetOverlayPositionData);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdSetOverlayPosition: Invalid surfaces or dwFlags\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(&puSetOverlayPositionData->ddRVal,
|
|
SetOverlayPositionData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdGetScanLine
|
|
*
|
|
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdGetScanLine(
|
|
HANDLE hDirectDraw,
|
|
PDD_GETSCANLINEDATA puGetScanLineData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETSCANLINEDATA GetScanLineData;
|
|
|
|
__try
|
|
{
|
|
GetScanLineData = ProbeAndReadStructure(puGetScanLineData,
|
|
DD_GETSCANLINEDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
GetScanLineData.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;
|
|
|
|
if (peDirectDrawGlobal->CallBacks.dwFlags & DDHAL_CB32_GETSCANLINE)
|
|
{
|
|
GetScanLineData.lpDD = peDirectDrawGlobal;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (peDirectDrawGlobal->bSuspended)
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
GetScanLineData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
CallBacks.GetScanLine(&GetScanLineData);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetScanLine: Invalid object or dwFlags\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(&puGetScanLineData->ddRVal,
|
|
GetScanLineData.ddRVal);
|
|
ProbeAndWriteUlong(&puGetScanLineData->dwScanLine,
|
|
GetScanLineData.dwScanLine);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdSetExclusiveMode
|
|
*
|
|
* 22-Apr-1998 -by- John Stephens [johnstep]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdSetExclusiveMode(
|
|
HANDLE hDirectDraw,
|
|
PDD_SETEXCLUSIVEMODEDATA puSetExclusiveModeData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_SETEXCLUSIVEMODEDATA SetExclusiveModeData;
|
|
|
|
__try
|
|
{
|
|
SetExclusiveModeData = ProbeAndReadStructure(puSetExclusiveModeData,
|
|
DD_SETEXCLUSIVEMODEDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
SetExclusiveModeData.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;
|
|
|
|
if (peDirectDrawGlobal->NTCallBacks.dwFlags &
|
|
DDHAL_NTCB32_SETEXCLUSIVEMODE)
|
|
{
|
|
SetExclusiveModeData.lpDD = peDirectDrawGlobal;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (!peDirectDrawGlobal->bSuspended)
|
|
{
|
|
dwRet = peDirectDrawGlobal->NTCallBacks.
|
|
SetExclusiveMode(&SetExclusiveModeData);
|
|
}
|
|
else
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
WARNING("DxDdSetExclusiveMode: "
|
|
"Can't set exclusive mode because disabled\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdSetExclusiveMode: Invalid object or dwFlags\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(&puSetExclusiveModeData->ddRVal,
|
|
SetExclusiveModeData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdFlipToGDISurface
|
|
*
|
|
* 22-Apr-1998 -by- John Stephens [johnstep]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdFlipToGDISurface(
|
|
HANDLE hDirectDraw,
|
|
PDD_FLIPTOGDISURFACEDATA puFlipToGDISurfaceData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_FLIPTOGDISURFACEDATA FlipToGDISurfaceData;
|
|
|
|
__try
|
|
{
|
|
FlipToGDISurfaceData = ProbeAndReadStructure(puFlipToGDISurfaceData,
|
|
DD_FLIPTOGDISURFACEDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
FlipToGDISurfaceData.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;
|
|
|
|
if (peDirectDrawGlobal->NTCallBacks.dwFlags &
|
|
DDHAL_NTCB32_FLIPTOGDISURFACE)
|
|
{
|
|
FlipToGDISurfaceData.lpDD = peDirectDrawGlobal;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (!peDirectDrawGlobal->bSuspended)
|
|
{
|
|
dwRet = peDirectDrawGlobal->NTCallBacks.
|
|
FlipToGDISurface(&FlipToGDISurfaceData);
|
|
}
|
|
else
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
WARNING("DxDdFlipToGDISurface: "
|
|
"Can't flip because disabled\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdFlipToGDISurface: Invalid object or dwFlags\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(&puFlipToGDISurfaceData->ddRVal,
|
|
FlipToGDISurfaceData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDdGetVailDriverMemory
|
|
*
|
|
* History:
|
|
* 16-Feb-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdGetAvailDriverMemory(
|
|
HANDLE hDirectDraw,
|
|
PDD_GETAVAILDRIVERMEMORYDATA puGetAvailDriverMemoryData
|
|
)
|
|
{
|
|
DD_GETAVAILDRIVERMEMORYDATA GetAvailDriverMemoryData;
|
|
DWORD dwHeap;
|
|
VIDEOMEMORY* pHeap;
|
|
DWORD dwAllocated = 0;
|
|
DWORD dwFree = 0;
|
|
|
|
__try
|
|
{
|
|
GetAvailDriverMemoryData
|
|
= ProbeAndReadStructure(puGetAvailDriverMemoryData,
|
|
DD_GETAVAILDRIVERMEMORYDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
GetAvailDriverMemoryData.ddRVal = DD_OK;
|
|
GetAvailDriverMemoryData.dwTotal = 0;
|
|
GetAvailDriverMemoryData.dwFree = 0;
|
|
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
// First count up all the memory for the heaps we control in kernel.
|
|
pHeap = peDirectDrawGlobal->pvmList;
|
|
for (dwHeap = 0;
|
|
dwHeap < peDirectDrawGlobal->dwNumHeaps;
|
|
pHeap++, dwHeap++)
|
|
{
|
|
/*
|
|
* We use ddsCapsAlt as we wish to return the total amount
|
|
* of memory of the given type it is possible to allocate
|
|
* regardless of whether it is desirable to allocate that
|
|
* type of memory from a given heap or not.
|
|
*/
|
|
if( (pHeap->dwFlags & VIDMEM_HEAPDISABLED) == 0 &&
|
|
(GetAvailDriverMemoryData.DDSCaps.dwCaps &
|
|
pHeap->ddsCapsAlt.dwCaps) == 0 )
|
|
{
|
|
dwFree += VidMemAmountFree( pHeap->lpHeap );
|
|
dwAllocated += VidMemAmountAllocated( pHeap->lpHeap );
|
|
}
|
|
}
|
|
|
|
if (peDirectDrawGlobal->MiscellaneousCallBacks.dwFlags &
|
|
DDHAL_MISCCB32_GETAVAILDRIVERMEMORY)
|
|
{
|
|
GetAvailDriverMemoryData.lpDD = peDirectDrawGlobal;
|
|
|
|
if (peDirectDrawGlobal->bSuspended)
|
|
{
|
|
GetAvailDriverMemoryData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else
|
|
{
|
|
peDirectDrawGlobal->MiscellaneousCallBacks.
|
|
GetAvailDriverMemory(&GetAvailDriverMemoryData);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetAvailDriverMemory: Invalid object or dwFlags\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(&puGetAvailDriverMemoryData->ddRVal,
|
|
GetAvailDriverMemoryData.ddRVal);
|
|
ProbeAndWriteUlong(&puGetAvailDriverMemoryData->dwTotal,
|
|
GetAvailDriverMemoryData.dwTotal + dwAllocated + dwFree);
|
|
ProbeAndWriteUlong(&puGetAvailDriverMemoryData->dwFree,
|
|
GetAvailDriverMemoryData.dwFree + dwFree);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDdColorControl
|
|
*
|
|
* Not to be confused with the VideoPort ColorControl function.
|
|
*
|
|
* History:
|
|
* 16-Feb-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdColorControl(
|
|
HANDLE hSurface,
|
|
PDD_COLORCONTROLDATA puColorControlData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_COLORCONTROLDATA ColorControlData;
|
|
DDCOLORCONTROL ColorInfo;
|
|
|
|
__try
|
|
{
|
|
ColorControlData = ProbeAndReadStructure(puColorControlData,
|
|
DD_COLORCONTROLDATA);
|
|
ColorInfo = ProbeAndReadStructure(ColorControlData.lpColorData,
|
|
DDCOLORCONTROL);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
ColorControlData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_SURFACE* peSurface;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if ((peSurface != NULL) &&
|
|
!(peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
|
|
{
|
|
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
|
|
|
|
// NOTE: For security, gotta reset when switching desktops
|
|
|
|
if (peDirectDrawGlobal->ColorControlCallBacks.dwFlags &
|
|
DDHAL_COLOR_COLORCONTROL)
|
|
{
|
|
ColorControlData.lpDD = peDirectDrawGlobal;
|
|
ColorControlData.lpDDSurface = peSurface;
|
|
ColorControlData.lpColorData = &ColorInfo;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (peSurface->bLost)
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
ColorControlData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else
|
|
{
|
|
dwRet = peDirectDrawGlobal->
|
|
ColorControlCallBacks.ColorControl(&ColorControlData);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxColorControl: Invalid surface or dwFlags\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(&puColorControlData->ddRVal, ColorControlData.ddRVal);
|
|
ProbeAndWriteStructure(ColorControlData.lpColorData,
|
|
ColorInfo,
|
|
DDCOLORCONTROL);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* DWORD DxDdGetDriverInfo
|
|
*
|
|
* History:
|
|
* 16-Feb-1997 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdGetDriverInfo(
|
|
HANDLE hDirectDraw,
|
|
PDD_GETDRIVERINFODATA puGetDriverInfoData
|
|
)
|
|
{
|
|
DD_GETDRIVERINFODATA GetDriverInfoData;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
GUID* pGuid;
|
|
VOID* pvData;
|
|
ULONG cjData;
|
|
// Needed for Z-Pixels and others which don't cache information
|
|
// in the global.
|
|
// 1K should be enough for about 30 DDPIXELFORMATS,
|
|
// which should be plenty
|
|
DWORD adwBuffer[256];
|
|
|
|
__try
|
|
{
|
|
GetDriverInfoData = ProbeAndReadStructure(puGetDriverInfoData,
|
|
DD_GETDRIVERINFODATA);
|
|
|
|
// Assume failure:
|
|
|
|
puGetDriverInfoData->ddRVal = DDERR_GENERIC;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
pGuid = &GetDriverInfoData.guidInfo;
|
|
pvData = NULL;
|
|
|
|
// Note that the actual addresses of the call-backs won't be of
|
|
// much interest to user-mode DirectDraw, but it will still use the
|
|
// dwFlags field of the CALLBACKS structure.
|
|
|
|
if (IsEqualIID(pGuid, &GUID_VideoPortCallbacks) &&
|
|
(peDirectDrawGlobal->flDriverInfo & DD_DRIVERINFO_VIDEOPORT))
|
|
{
|
|
pvData = &peDirectDrawGlobal->VideoPortCallBacks;
|
|
cjData = sizeof(peDirectDrawGlobal->VideoPortCallBacks);
|
|
}
|
|
|
|
if (IsEqualIID(pGuid, &GUID_VideoPortCaps) &&
|
|
(peDirectDrawGlobal->flDriverInfo & DD_DRIVERINFO_VIDEOPORT))
|
|
{
|
|
pvData = peDirectDrawGlobal->lpDDVideoPortCaps;
|
|
cjData = peDirectDrawGlobal->HalInfo.ddCaps.dwMaxVideoPorts
|
|
* sizeof(DDVIDEOPORTCAPS);
|
|
}
|
|
|
|
if (IsEqualIID(pGuid, &GUID_KernelCaps) )
|
|
{
|
|
pvData = &(peDirectDrawGlobal->DDKernelCaps);
|
|
cjData = sizeof(DDKERNELCAPS);
|
|
}
|
|
|
|
if (IsEqualIID(pGuid, &GUID_ColorControlCallbacks) &&
|
|
(peDirectDrawGlobal->flDriverInfo & DD_DRIVERINFO_COLORCONTROL))
|
|
{
|
|
pvData = &peDirectDrawGlobal->ColorControlCallBacks;
|
|
cjData = sizeof(peDirectDrawGlobal->ColorControlCallBacks);
|
|
}
|
|
|
|
if (IsEqualIID(pGuid, &GUID_MiscellaneousCallbacks) &&
|
|
(peDirectDrawGlobal->flDriverInfo & DD_DRIVERINFO_MISCELLANEOUS))
|
|
{
|
|
pvData = &peDirectDrawGlobal->MiscellaneousCallBacks;
|
|
cjData = sizeof(peDirectDrawGlobal->MiscellaneousCallBacks);
|
|
}
|
|
|
|
if (IsEqualIID(pGuid, &GUID_Miscellaneous2Callbacks) &&
|
|
(peDirectDrawGlobal->flDriverInfo & DD_DRIVERINFO_MISCELLANEOUS2))
|
|
{
|
|
pvData = &peDirectDrawGlobal->Miscellaneous2CallBacks;
|
|
cjData = sizeof(peDirectDrawGlobal->Miscellaneous2CallBacks);
|
|
}
|
|
|
|
if (IsEqualIID(pGuid, &GUID_NTCallbacks) &&
|
|
(peDirectDrawGlobal->flDriverInfo & DD_DRIVERINFO_NT))
|
|
{
|
|
pvData = &peDirectDrawGlobal->NTCallBacks;
|
|
cjData = sizeof(peDirectDrawGlobal->NTCallBacks);
|
|
}
|
|
|
|
if (IsEqualIID(pGuid, &GUID_D3DCallbacks3) &&
|
|
(peDirectDrawGlobal->flDriverInfo & DD_DRIVERINFO_D3DCALLBACKS3))
|
|
{
|
|
pvData = &peDirectDrawGlobal->D3dCallBacks3;
|
|
cjData = sizeof(peDirectDrawGlobal->D3dCallBacks3);
|
|
}
|
|
|
|
if (IsEqualIID(pGuid, &GUID_MotionCompCallbacks) &&
|
|
(peDirectDrawGlobal->flDriverInfo & DD_DRIVERINFO_MOTIONCOMP))
|
|
{
|
|
pvData = &peDirectDrawGlobal->MotionCompCallbacks;
|
|
cjData = sizeof(peDirectDrawGlobal->MotionCompCallbacks);
|
|
}
|
|
|
|
if (IsEqualIID(pGuid, &GUID_DDMoreCaps) &&
|
|
(peDirectDrawGlobal->flDriverInfo & DD_DRIVERINFO_MORECAPS))
|
|
{
|
|
pvData = &peDirectDrawGlobal->MoreCaps;
|
|
cjData = sizeof(peDirectDrawGlobal->MoreCaps);
|
|
}
|
|
|
|
if (IsEqualIID(pGuid, &GUID_DDMoreSurfaceCaps))
|
|
{
|
|
pvData = &peDirectDrawGlobal->MoreSurfaceCaps;
|
|
cjData = sizeof(DD_MORESURFACECAPS)-2*sizeof(DDSCAPSEX);
|
|
}
|
|
//
|
|
// The information for the following GUIDs does not
|
|
// need to be kept around in the kernel so the call
|
|
// is passed directly to the driver.
|
|
//
|
|
|
|
if (pvData == NULL)
|
|
{
|
|
cjData = 0;
|
|
|
|
if (IsEqualIID(pGuid, &GUID_D3DExtendedCaps))
|
|
{
|
|
cjData = sizeof(D3DNTHAL_D3DEXTENDEDCAPS);
|
|
}
|
|
|
|
if (IsEqualIID(pGuid, &GUID_ZPixelFormats))
|
|
{
|
|
cjData = sizeof(adwBuffer);
|
|
}
|
|
|
|
if (IsEqualIID(pGuid, &GUID_NonLocalVidMemCaps))
|
|
{
|
|
cjData = sizeof(DD_NONLOCALVIDMEMCAPS);
|
|
}
|
|
|
|
if (IsEqualIID(pGuid, &GUID_DDStereoMode))
|
|
{
|
|
cjData = sizeof(DD_STEREOMODE);
|
|
__try
|
|
{
|
|
ProbeForRead(GetDriverInfoData.lpvData, cjData, sizeof(ULONG));
|
|
RtlCopyMemory(adwBuffer, GetDriverInfoData.lpvData, cjData);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
}
|
|
|
|
if (cjData > 0)
|
|
{
|
|
ASSERTGDI(sizeof(adwBuffer) >= cjData,
|
|
"adwBuffer too small");
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (bDdGetDriverInfo(peDirectDrawGlobal, pGuid,
|
|
adwBuffer, cjData, &cjData))
|
|
{
|
|
pvData = adwBuffer;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pvData != NULL)
|
|
{
|
|
__try
|
|
{
|
|
|
|
ProbeForWrite(GetDriverInfoData.lpvData, cjData, sizeof(ULONG));
|
|
|
|
RtlCopyMemory(GetDriverInfoData.lpvData, pvData, cjData);
|
|
|
|
ProbeAndWriteUlong(&puGetDriverInfoData->dwActualSize, cjData);
|
|
ProbeAndWriteRVal(&puGetDriverInfoData->ddRVal, DD_OK);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetDriverInfo: Invalid object\n");
|
|
}
|
|
|
|
return(DDHAL_DRIVER_HANDLED);
|
|
}
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdGetDxHandle
|
|
*
|
|
* 18-Oct-1997 -by- smac
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HANDLE
|
|
APIENTRY
|
|
DxDdGetDxHandle(
|
|
HANDLE hDirectDraw,
|
|
HANDLE hSurface,
|
|
BOOL bRelease
|
|
)
|
|
{
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
EDD_SURFACE* peSurface;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
HANDLE hRet;
|
|
|
|
hRet = NULL;
|
|
|
|
if( hDirectDraw != NULL )
|
|
{
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
|
|
if( peDirectDrawLocal != NULL )
|
|
{
|
|
// Use the devlock to synchronize additions and deletions to
|
|
// the attach list:
|
|
|
|
EDD_DEVLOCK eDevLock(peDirectDrawLocal->peDirectDrawGlobal);
|
|
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
if( !bRelease )
|
|
{
|
|
if( bDdLoadDxApi( peDirectDrawLocal ) &&
|
|
( peDirectDrawGlobal->hDirectDraw != NULL ) )
|
|
{
|
|
hRet = hDirectDraw;
|
|
peDirectDrawGlobal->dwDxApiExplicitLoads++;
|
|
}
|
|
}
|
|
else if( ( peDirectDrawGlobal->hDirectDraw != NULL ) && bRelease &&
|
|
( peDirectDrawGlobal->dwDxApiExplicitLoads > 0 ) )
|
|
{
|
|
vDdUnloadDxApi( peDirectDrawGlobal );
|
|
hRet = hDirectDraw;
|
|
peDirectDrawGlobal->dwDxApiExplicitLoads--;
|
|
}
|
|
}
|
|
}
|
|
|
|
else if( hSurface != NULL )
|
|
{
|
|
peSurface = eLockSurface.peLock(hSurface);
|
|
if( peSurface != NULL )
|
|
{
|
|
// Use the devlock to synchronize additions and deletions to
|
|
// the attach list:
|
|
|
|
EDD_DEVLOCK eDevLock(peSurface->peDirectDrawGlobal);
|
|
|
|
// They must open the DirectDraw handle before opening the
|
|
// surface handle, otherwise we fail.
|
|
|
|
if( peSurface->peDirectDrawGlobal->hDirectDraw != NULL )
|
|
{
|
|
if ((peSurface->bLost) ||
|
|
(peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
|
|
{
|
|
WARNING("DxDdGetDxHandle: Video surface is bad/lost/system");
|
|
}
|
|
else if( ( peSurface->hSurface == NULL ) && !bRelease )
|
|
{
|
|
peSurface->hSurface = hDdOpenDxApiSurface( peSurface );
|
|
if( peSurface->hSurface != NULL )
|
|
{
|
|
hRet = hSurface;
|
|
}
|
|
}
|
|
else if( ( peSurface->hSurface != NULL ) && bRelease )
|
|
{
|
|
vDdCloseDxApiSurface( peSurface );
|
|
hRet = hSurface;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( hRet );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdGetMoCompGuids
|
|
*
|
|
* 18-Nov-1997 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdGetMoCompGuids(
|
|
HANDLE hDirectDraw,
|
|
PDD_GETMOCOMPGUIDSDATA puGetMoCompGuidsData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETMOCOMPGUIDSDATA GetMoCompGuidsData;
|
|
LPGUID puGuids;
|
|
ULONG cjGuids;
|
|
HANDLE hSecure;
|
|
|
|
__try
|
|
{
|
|
GetMoCompGuidsData
|
|
= ProbeAndReadStructure(puGetMoCompGuidsData,
|
|
DD_GETMOCOMPGUIDSDATA);
|
|
|
|
puGuids = GetMoCompGuidsData.lpGuids;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
GetMoCompGuidsData.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;
|
|
|
|
GetMoCompGuidsData.lpDD = peDirectDrawGlobal;
|
|
GetMoCompGuidsData.dwNumGuids = 0;
|
|
GetMoCompGuidsData.lpGuids = NULL;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->MotionCompCallbacks.GetMoCompGuids))
|
|
{
|
|
dwRet = peDirectDrawGlobal->MotionCompCallbacks.
|
|
GetMoCompGuids(&GetMoCompGuidsData);
|
|
|
|
cjGuids = GetMoCompGuidsData.dwNumGuids
|
|
* sizeof(GUID);
|
|
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(GetMoCompGuidsData.ddRVal == DD_OK) &&
|
|
(cjGuids > 0) &&
|
|
(puGuids != NULL))
|
|
{
|
|
hSecure = 0;
|
|
GetMoCompGuidsData.ddRVal = DDERR_GENERIC;
|
|
|
|
__try
|
|
{
|
|
ProbeForWrite(puGuids, cjGuids, sizeof(UCHAR));
|
|
|
|
hSecure = MmSecureVirtualMemory(puGuids,
|
|
cjGuids,
|
|
PAGE_READWRITE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
if (hSecure)
|
|
{
|
|
GetMoCompGuidsData.lpGuids = puGuids;
|
|
|
|
dwRet = peDirectDrawGlobal->MotionCompCallbacks.
|
|
GetMoCompGuids(&GetMoCompGuidsData);
|
|
|
|
MmUnsecureVirtualMemory(hSecure);
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetMoCompGuids: Bad destination buffer\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetMoCompGuids: 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(&puGetMoCompGuidsData->ddRVal,
|
|
GetMoCompGuidsData.ddRVal);
|
|
ProbeAndWriteUlong(&puGetMoCompGuidsData->dwNumGuids,
|
|
GetMoCompGuidsData.dwNumGuids);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdGetMoCompFormats
|
|
*
|
|
* 18-Nov-1997 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdGetMoCompFormats(
|
|
HANDLE hDirectDraw,
|
|
PDD_GETMOCOMPFORMATSDATA puGetMoCompFormatsData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETMOCOMPFORMATSDATA GetMoCompFormatsData;
|
|
GUID guid;
|
|
LPDDPIXELFORMAT puFormats;
|
|
ULONG cjFormats;
|
|
HANDLE hSecure;
|
|
|
|
__try
|
|
{
|
|
GetMoCompFormatsData
|
|
= ProbeAndReadStructure(puGetMoCompFormatsData,
|
|
DD_GETMOCOMPFORMATSDATA);
|
|
guid = ProbeAndReadStructure(GetMoCompFormatsData.lpGuid,
|
|
GUID);
|
|
GetMoCompFormatsData.lpGuid = &guid;
|
|
|
|
puFormats = GetMoCompFormatsData.lpFormats;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
GetMoCompFormatsData.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;
|
|
|
|
GetMoCompFormatsData.lpDD = peDirectDrawGlobal;
|
|
GetMoCompFormatsData.dwNumFormats = 0;
|
|
GetMoCompFormatsData.lpFormats = NULL;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->MotionCompCallbacks.GetMoCompFormats))
|
|
{
|
|
dwRet = peDirectDrawGlobal->MotionCompCallbacks.
|
|
GetMoCompFormats(&GetMoCompFormatsData);
|
|
|
|
cjFormats = GetMoCompFormatsData.dwNumFormats
|
|
* sizeof(DDPIXELFORMAT);
|
|
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(GetMoCompFormatsData.ddRVal == DD_OK) &&
|
|
(cjFormats > 0) &&
|
|
(puFormats != NULL))
|
|
{
|
|
hSecure = 0;
|
|
GetMoCompFormatsData.ddRVal = DDERR_GENERIC;
|
|
|
|
__try
|
|
{
|
|
ProbeForWrite(puFormats, cjFormats, sizeof(UCHAR));
|
|
|
|
hSecure = MmSecureVirtualMemory(puFormats,
|
|
cjFormats,
|
|
PAGE_READWRITE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
if (hSecure)
|
|
{
|
|
GetMoCompFormatsData.lpFormats = puFormats;
|
|
|
|
dwRet = peDirectDrawGlobal->MotionCompCallbacks.
|
|
GetMoCompFormats(&GetMoCompFormatsData);
|
|
|
|
MmUnsecureVirtualMemory(hSecure);
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetMoCompFormats: Bad destination buffer\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetMoCompFormats: 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(&puGetMoCompFormatsData->ddRVal,
|
|
GetMoCompFormatsData.ddRVal);
|
|
ProbeAndWriteUlong(&puGetMoCompFormatsData->dwNumFormats,
|
|
GetMoCompFormatsData.dwNumFormats);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bDdDeleteMotionCompObject
|
|
*
|
|
* Deletes a kernel-mode representation of the motion comp object.
|
|
*
|
|
* 19-Nov-1997 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bDdDeleteMotionCompObject(
|
|
HANDLE hMotionComp,
|
|
DWORD* pdwRet // For returning driver return code, may be NULL
|
|
)
|
|
{
|
|
BOOL bRet;
|
|
DWORD dwRet;
|
|
EDD_MOTIONCOMP* peMotionComp;
|
|
EDD_MOTIONCOMP* peTmp;
|
|
VOID* pvRemove;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
DD_DESTROYMOCOMPDATA DestroyMoCompData;
|
|
DXOBJ* pDxObj;
|
|
DXOBJ* pDxObjNext;
|
|
|
|
bRet = FALSE;
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
|
|
peMotionComp = (EDD_MOTIONCOMP*) DdHmgLock((HDD_OBJ) hMotionComp, DD_MOTIONCOMP_TYPE, FALSE);
|
|
|
|
if (peMotionComp != NULL)
|
|
{
|
|
peDirectDrawGlobal = peMotionComp->peDirectDrawGlobal;
|
|
|
|
pvRemove = DdHmgRemoveObject((HDD_OBJ) hMotionComp,
|
|
DdHmgQueryLock((HDD_OBJ) hMotionComp),
|
|
0,
|
|
TRUE,
|
|
DD_MOTIONCOMP_TYPE);
|
|
|
|
// Hold the devlock while we call the driver and while we muck
|
|
// around in the motion comp list:
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if (peMotionComp->fl & DD_MOTIONCOMP_FLAG_DRIVER_CREATED)
|
|
{
|
|
// Call the driver if it created the object:
|
|
|
|
if (peDirectDrawGlobal->MotionCompCallbacks.DestroyMoComp)
|
|
{
|
|
DestroyMoCompData.lpDD = peDirectDrawGlobal;
|
|
DestroyMoCompData.lpMoComp = peMotionComp;
|
|
DestroyMoCompData.ddRVal = DDERR_GENERIC;
|
|
|
|
dwRet = peDirectDrawGlobal->
|
|
MotionCompCallbacks.DestroyMoComp(&DestroyMoCompData);
|
|
}
|
|
}
|
|
|
|
// Remove from the motion comp object from linked-list:
|
|
|
|
peDirectDrawLocal = peMotionComp->peDirectDrawLocal;
|
|
|
|
if (peDirectDrawLocal->peMotionComp_DdList == peMotionComp)
|
|
{
|
|
peDirectDrawLocal->peMotionComp_DdList
|
|
= peMotionComp->peMotionComp_DdNext;
|
|
}
|
|
else
|
|
{
|
|
for (peTmp = peDirectDrawLocal->peMotionComp_DdList;
|
|
( peTmp != NULL)&&(peTmp->peMotionComp_DdNext != peMotionComp);
|
|
peTmp = peTmp->peMotionComp_DdNext)
|
|
;
|
|
|
|
if( peTmp != NULL )
|
|
{
|
|
peTmp->peMotionComp_DdNext = peMotionComp->peMotionComp_DdNext;
|
|
}
|
|
}
|
|
|
|
// We're all done with this object, so free the memory and
|
|
// leave:
|
|
|
|
DdFreeObject(peMotionComp, DD_MOTIONCOMP_TYPE);
|
|
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING1("bDdDeleteMotionComp: Bad handle or object was busy\n");
|
|
}
|
|
|
|
if (pdwRet != NULL)
|
|
{
|
|
*pdwRet = dwRet;
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdCreateMoComp
|
|
*
|
|
* 18-Nov-1997 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HANDLE
|
|
APIENTRY
|
|
DxDdCreateMoComp(
|
|
HANDLE hDirectDraw,
|
|
PDD_CREATEMOCOMPDATA puCreateMoCompData
|
|
)
|
|
{
|
|
HANDLE hRet;
|
|
DWORD dwRet;
|
|
DD_CREATEMOCOMPDATA CreateMoCompData;
|
|
GUID guid;
|
|
PBYTE puData;
|
|
ULONG cjData;
|
|
HANDLE hSecure;
|
|
|
|
__try
|
|
{
|
|
CreateMoCompData =
|
|
ProbeAndReadStructure(puCreateMoCompData,
|
|
DD_CREATEMOCOMPDATA);
|
|
|
|
guid = ProbeAndReadStructure(CreateMoCompData.lpGuid,
|
|
GUID);
|
|
CreateMoCompData.lpGuid = &guid;
|
|
|
|
puData = (PBYTE) CreateMoCompData.lpData;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
hRet = NULL;
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
CreateMoCompData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_MOTIONCOMP* peMotionComp;
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
|
|
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.
|
|
|
|
peMotionComp = (EDD_MOTIONCOMP*) DdHmgAlloc(sizeof(EDD_MOTIONCOMP),
|
|
DD_MOTIONCOMP_TYPE,
|
|
HMGR_ALLOC_LOCK);
|
|
if (peMotionComp)
|
|
{
|
|
// Private data:
|
|
|
|
peMotionComp->peDirectDrawGlobal = peDirectDrawGlobal;
|
|
peMotionComp->peDirectDrawLocal = peDirectDrawLocal;
|
|
cjData = CreateMoCompData.dwDataSize;
|
|
|
|
// Public data:
|
|
|
|
peMotionComp->lpDD = peDirectDrawGlobal;
|
|
RtlCopyMemory(&(peMotionComp->guid),
|
|
&guid,
|
|
sizeof(GUID));
|
|
peMotionComp->dwUncompWidth = CreateMoCompData.dwUncompWidth;
|
|
peMotionComp->dwUncompHeight = CreateMoCompData.dwUncompHeight;
|
|
RtlCopyMemory(&(peMotionComp->ddUncompPixelFormat),
|
|
&CreateMoCompData.ddUncompPixelFormat,
|
|
sizeof(DDPIXELFORMAT));
|
|
|
|
// Hold devlock for driver call
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
// Add this videoport to the list hanging off the
|
|
// DirectDrawLocal object allocated for this process:
|
|
|
|
peMotionComp->peMotionComp_DdNext
|
|
= peDirectDrawLocal->peMotionComp_DdList;
|
|
peDirectDrawLocal->peMotionComp_DdList
|
|
= peMotionComp;
|
|
|
|
// Now call the driver to create its version:
|
|
|
|
CreateMoCompData.lpDD = peDirectDrawGlobal;
|
|
CreateMoCompData.lpMoComp = peMotionComp;
|
|
CreateMoCompData.ddRVal = DDERR_GENERIC;
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED; // Call is optional
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->MotionCompCallbacks.CreateMoComp))
|
|
{
|
|
hSecure = 0;
|
|
if( puData )
|
|
{
|
|
__try
|
|
{
|
|
ProbeForWrite(puData, cjData, sizeof(UCHAR));
|
|
|
|
hSecure = MmSecureVirtualMemory(puData,
|
|
cjData,
|
|
PAGE_READWRITE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
if( ( puData == NULL ) || hSecure )
|
|
{
|
|
CreateMoCompData.lpData = puData;
|
|
|
|
dwRet = peDirectDrawGlobal->MotionCompCallbacks.
|
|
CreateMoComp(&CreateMoCompData);
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdCreateMoComp: Bad data buffer\n");
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
}
|
|
|
|
if( hSecure )
|
|
{
|
|
MmUnsecureVirtualMemory(hSecure);
|
|
}
|
|
if ((CreateMoCompData.ddRVal == DD_OK))
|
|
{
|
|
peMotionComp->fl |= DD_MOTIONCOMP_FLAG_DRIVER_CREATED;
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdCreateMoComp: Driver failed call\n");
|
|
}
|
|
}
|
|
if ((dwRet == DDHAL_DRIVER_NOTHANDLED) ||
|
|
(CreateMoCompData.ddRVal == DD_OK))
|
|
{
|
|
CreateMoCompData.ddRVal = DD_OK;
|
|
hRet = peMotionComp->hGet();
|
|
DEC_EXCLUSIVE_REF_CNT( peMotionComp );
|
|
}
|
|
else
|
|
{
|
|
bDdDeleteMotionCompObject(peMotionComp->hGet(), NULL);
|
|
|
|
CreateMoCompData.ddRVal = DDERR_GENERIC;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdCreateMoComp: Bad parameters\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdCreateMoComp: 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(&puCreateMoCompData->ddRVal, CreateMoCompData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
// Note that the user-mode stub always returns DDHAL_DRIVER_HANDLED
|
|
// to DirectDraw.
|
|
|
|
return(hRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdGetMoCompBuffInfo
|
|
*
|
|
* 17-Jun-1998 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdGetMoCompBuffInfo(
|
|
HANDLE hDirectDraw,
|
|
PDD_GETMOCOMPCOMPBUFFDATA puGetBuffData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETMOCOMPCOMPBUFFDATA GetBuffData;
|
|
LPDDCOMPBUFFERINFO puBuffInfo;
|
|
GUID guid;
|
|
ULONG cjNumTypes;
|
|
HANDLE hSecure;
|
|
|
|
__try
|
|
{
|
|
GetBuffData =
|
|
ProbeAndReadStructure(puGetBuffData,
|
|
DD_GETMOCOMPCOMPBUFFDATA);
|
|
guid = ProbeAndReadStructure(GetBuffData.lpGuid,
|
|
GUID);
|
|
GetBuffData.lpGuid = &guid;
|
|
puBuffInfo = GetBuffData.lpCompBuffInfo;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
GetBuffData.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;
|
|
|
|
GetBuffData.lpDD = peDirectDrawGlobal;
|
|
GetBuffData.dwNumTypesCompBuffs = 0;
|
|
GetBuffData.lpCompBuffInfo = NULL;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->MotionCompCallbacks.GetMoCompBuffInfo))
|
|
{
|
|
dwRet = peDirectDrawGlobal->MotionCompCallbacks.
|
|
GetMoCompBuffInfo(&GetBuffData);
|
|
|
|
cjNumTypes = GetBuffData.dwNumTypesCompBuffs *
|
|
sizeof(DDCOMPBUFFERINFO);
|
|
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(GetBuffData.ddRVal == DD_OK) &&
|
|
(cjNumTypes > 0) &&
|
|
(puBuffInfo != NULL))
|
|
{
|
|
hSecure = 0;
|
|
GetBuffData.ddRVal = DDERR_GENERIC;
|
|
|
|
__try
|
|
{
|
|
ProbeForWrite(puBuffInfo, cjNumTypes, sizeof(UCHAR));
|
|
|
|
hSecure = MmSecureVirtualMemory(puBuffInfo,
|
|
cjNumTypes,
|
|
PAGE_READWRITE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
if (hSecure)
|
|
{
|
|
GetBuffData.lpCompBuffInfo = puBuffInfo;
|
|
|
|
dwRet = peDirectDrawGlobal->MotionCompCallbacks.
|
|
GetMoCompBuffInfo(&GetBuffData);
|
|
|
|
MmUnsecureVirtualMemory(hSecure);
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetMoCompBuffInfo: Bad destination buffer\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetMoCompBuffInfo: 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(&puGetBuffData->ddRVal,
|
|
GetBuffData.ddRVal);
|
|
ProbeAndWriteUlong(&puGetBuffData->dwNumTypesCompBuffs,
|
|
GetBuffData.dwNumTypesCompBuffs);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdGetInternalMoCompInfo
|
|
*
|
|
* 17-Jun-1998 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdGetInternalMoCompInfo(
|
|
HANDLE hDirectDraw,
|
|
PDD_GETINTERNALMOCOMPDATA puGetInternalData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_GETINTERNALMOCOMPDATA GetInternalData;
|
|
GUID guid;
|
|
|
|
__try
|
|
{
|
|
GetInternalData =
|
|
ProbeAndReadStructure(puGetInternalData,
|
|
DD_GETINTERNALMOCOMPDATA);
|
|
guid = ProbeAndReadStructure(GetInternalData.lpGuid,
|
|
GUID);
|
|
GetInternalData.lpGuid = &guid;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
GetInternalData.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;
|
|
|
|
GetInternalData.lpDD = peDirectDrawGlobal;
|
|
GetInternalData.dwScratchMemAlloc = 0;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->MotionCompCallbacks.GetInternalMoCompInfo))
|
|
{
|
|
dwRet = peDirectDrawGlobal->MotionCompCallbacks.
|
|
GetInternalMoCompInfo(&GetInternalData);
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdGetInternalMoCompInfo: 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(&puGetInternalData->ddRVal,
|
|
GetInternalData.ddRVal);
|
|
ProbeAndWriteUlong(&puGetInternalData->dwScratchMemAlloc,
|
|
GetInternalData.dwScratchMemAlloc);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdDestroyMoComp
|
|
*
|
|
* 18-Nov-1997 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdDestroyMoComp(
|
|
HANDLE hMoComp,
|
|
PDD_DESTROYMOCOMPDATA puDestroyMoCompData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
|
|
bDdDeleteMotionCompObject(hMoComp, &dwRet);
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteRVal(&puDestroyMoCompData->ddRVal, DD_OK);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdBeginMoCompFrame
|
|
*
|
|
* 18-Nov-1997 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdBeginMoCompFrame(
|
|
HANDLE hMoComp,
|
|
PDD_BEGINMOCOMPFRAMEDATA puBeginFrameData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_BEGINMOCOMPFRAMEDATA BeginFrameData;
|
|
LPBYTE puInputData;
|
|
ULONG cjInputData;
|
|
LPBYTE puOutputData;
|
|
ULONG cjOutputData;
|
|
ULONG cjRefData;
|
|
HANDLE hInputSecure;
|
|
HANDLE hOutputSecure;
|
|
DWORD dwNumRefSurfaces;
|
|
DWORD i;
|
|
DWORD j;
|
|
|
|
__try
|
|
{
|
|
BeginFrameData
|
|
= ProbeAndReadStructure(puBeginFrameData,
|
|
DD_BEGINMOCOMPFRAMEDATA);
|
|
|
|
puInputData = (PBYTE) BeginFrameData.lpInputData;
|
|
puOutputData = (PBYTE) BeginFrameData.lpOutputData;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
BeginFrameData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_MOTIONCOMP* peMotionComp;
|
|
EDD_LOCK_MOTIONCOMP eLockMotionComp;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_SURFACE* peSurfaceDest;
|
|
EDD_LOCK_SURFACE eLockSurfaceDest;
|
|
|
|
peSurfaceDest = eLockSurfaceDest.peLock(BeginFrameData.lpDestSurface);
|
|
peMotionComp = eLockMotionComp.peLock(hMoComp);
|
|
if ((peMotionComp != NULL) && (peSurfaceDest != NULL))
|
|
{
|
|
peDirectDrawGlobal = peMotionComp->peDirectDrawGlobal;
|
|
cjInputData = BeginFrameData.dwInputDataSize;
|
|
cjOutputData = BeginFrameData.dwOutputDataSize;
|
|
|
|
BeginFrameData.lpDD = peDirectDrawGlobal;
|
|
BeginFrameData.lpMoComp = peMotionComp;
|
|
BeginFrameData.lpDestSurface = peSurfaceDest;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->MotionCompCallbacks.BeginMoCompFrame))
|
|
{
|
|
// Secure the input buffer
|
|
hInputSecure = 0;
|
|
if( puInputData )
|
|
{
|
|
__try
|
|
{
|
|
ProbeForWrite(puInputData, cjInputData, sizeof(UCHAR));
|
|
|
|
hInputSecure = MmSecureVirtualMemory(puInputData,
|
|
cjInputData,
|
|
PAGE_READWRITE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
|
|
// Secure the output buffer
|
|
hOutputSecure = 0;
|
|
if( puOutputData )
|
|
{
|
|
__try
|
|
{
|
|
ProbeForWrite(puOutputData, cjOutputData, sizeof(UCHAR));
|
|
|
|
hOutputSecure = MmSecureVirtualMemory(puOutputData,
|
|
cjOutputData,
|
|
PAGE_READWRITE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
if( ( ( puInputData == NULL ) || hInputSecure ) &&
|
|
( ( puOutputData == NULL ) || hOutputSecure ) )
|
|
{
|
|
BeginFrameData.lpInputData = puInputData;
|
|
BeginFrameData.lpOutputData = puOutputData;
|
|
|
|
dwRet = peDirectDrawGlobal->MotionCompCallbacks.
|
|
BeginMoCompFrame(&BeginFrameData);
|
|
if ((BeginFrameData.ddRVal != DD_OK) &&
|
|
(dwRet == DDHAL_DRIVER_NOTHANDLED))
|
|
{
|
|
WARNING("DxDdBeginMoCompFrame: Driver failed callad\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdBeginMoCompFrame: Bad intput or output buffer\n");
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
}
|
|
|
|
if( hInputSecure )
|
|
{
|
|
MmUnsecureVirtualMemory(hInputSecure);
|
|
}
|
|
if( hOutputSecure )
|
|
{
|
|
MmUnsecureVirtualMemory(hOutputSecure);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdBeginMoCompFrame: 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(&puBeginFrameData->ddRVal,
|
|
BeginFrameData.ddRVal);
|
|
ProbeAndWriteUlong(&puBeginFrameData->dwOutputDataSize,
|
|
BeginFrameData.dwOutputDataSize);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdEndMoCompFrame
|
|
*
|
|
* 18-Nov-1997 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdEndMoCompFrame(
|
|
HANDLE hMoComp,
|
|
PDD_ENDMOCOMPFRAMEDATA puEndFrameData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_ENDMOCOMPFRAMEDATA EndFrameData;
|
|
LPBYTE puData;
|
|
ULONG cjData;
|
|
HANDLE hSecure;
|
|
|
|
__try
|
|
{
|
|
EndFrameData
|
|
= ProbeAndReadStructure(puEndFrameData,
|
|
DD_ENDMOCOMPFRAMEDATA);
|
|
|
|
puData = (PBYTE) EndFrameData.lpInputData;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
EndFrameData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_MOTIONCOMP* peMotionComp;
|
|
EDD_LOCK_MOTIONCOMP eLockMotionComp;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peMotionComp = eLockMotionComp.peLock(hMoComp);
|
|
if (peMotionComp != NULL)
|
|
{
|
|
peDirectDrawGlobal = peMotionComp->peDirectDrawGlobal;
|
|
cjData = EndFrameData.dwInputDataSize;
|
|
|
|
EndFrameData.lpDD = peDirectDrawGlobal;
|
|
EndFrameData.lpMoComp = peMotionComp;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->MotionCompCallbacks.EndMoCompFrame))
|
|
{
|
|
hSecure = 0;
|
|
if( puData )
|
|
{
|
|
__try
|
|
{
|
|
ProbeForWrite(puData, cjData, sizeof(UCHAR));
|
|
|
|
hSecure = MmSecureVirtualMemory(puData,
|
|
cjData,
|
|
PAGE_READWRITE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
if( ( puData == NULL ) || hSecure )
|
|
{
|
|
EndFrameData.lpInputData = puData;
|
|
|
|
dwRet = peDirectDrawGlobal->MotionCompCallbacks.
|
|
EndMoCompFrame(&EndFrameData);
|
|
if ((dwRet == DDHAL_DRIVER_HANDLED) &&
|
|
(EndFrameData.ddRVal != DD_OK))
|
|
{
|
|
WARNING("DxDdEndMoCompFrame: Driver failed call\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdEndMoCompFrame: Bad data buffer\n");
|
|
}
|
|
|
|
if( hSecure )
|
|
{
|
|
MmUnsecureVirtualMemory(hSecure);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdEndMoCompFrame: 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(&puEndFrameData->ddRVal,
|
|
EndFrameData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdRenderMoComp
|
|
*
|
|
* 18-Nov-1997 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdRenderMoComp(
|
|
HANDLE hMoComp,
|
|
PDD_RENDERMOCOMPDATA puRenderMoCompData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_RENDERMOCOMPDATA RenderMoCompData;
|
|
LPDDMOCOMPBUFFERINFO pMacroBlocks;
|
|
DWORD dwNumMacroBlocks;
|
|
LPBYTE puData;
|
|
ULONG cjData;
|
|
HANDLE hSecure;
|
|
LPBYTE puInputData;
|
|
ULONG cjInputData;
|
|
LPBYTE puOutputData;
|
|
ULONG cjOutputData;
|
|
DWORD i;
|
|
DWORD j;
|
|
|
|
__try
|
|
{
|
|
RenderMoCompData
|
|
= ProbeAndReadStructure(puRenderMoCompData,
|
|
DD_RENDERMOCOMPDATA);
|
|
|
|
pMacroBlocks = RenderMoCompData.lpBufferInfo;
|
|
dwNumMacroBlocks = RenderMoCompData.dwNumBuffers;
|
|
puInputData = (PBYTE) RenderMoCompData.lpInputData;
|
|
puOutputData = (PBYTE) RenderMoCompData.lpOutputData;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
RenderMoCompData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_MOTIONCOMP* peMotionComp;
|
|
EDD_LOCK_MOTIONCOMP eLockMotionComp;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peMotionComp = eLockMotionComp.peLock(hMoComp);
|
|
if (peMotionComp != NULL)
|
|
{
|
|
peDirectDrawGlobal = peMotionComp->peDirectDrawGlobal;
|
|
|
|
RenderMoCompData.lpDD = peDirectDrawGlobal;
|
|
RenderMoCompData.lpMoComp = peMotionComp;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->MotionCompCallbacks.RenderMoComp))
|
|
{
|
|
if (!BALLOC_OVERFLOW1(dwNumMacroBlocks, DDMOCOMPBUFFERINFO))
|
|
{
|
|
cjData = dwNumMacroBlocks * sizeof(DDMOCOMPBUFFERINFO);
|
|
hSecure = 0;
|
|
if (pMacroBlocks)
|
|
{
|
|
__try
|
|
{
|
|
ProbeForWrite(pMacroBlocks, cjData, sizeof(UCHAR));
|
|
|
|
hSecure = MmSecureVirtualMemory(pMacroBlocks,
|
|
cjData,
|
|
PAGE_READWRITE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
for (i = 0; i < dwNumMacroBlocks; i++)
|
|
{
|
|
// HmgLock return EDD_SURFACE, but we need a pointer to
|
|
// a DD_SURFACE_LOCAL, so we need to adjust by the size of
|
|
// an OBJECT. This means when releasing the lock, we need to
|
|
// reverse this adjustment.
|
|
|
|
pMacroBlocks[i].lpCompSurface = (PDD_SURFACE_LOCAL)
|
|
((LPBYTE)(DdHmgLock((HDD_OBJ)(pMacroBlocks[i].lpCompSurface), DD_SURFACE_TYPE, FALSE))
|
|
+ sizeof(DD_OBJECT));
|
|
if (pMacroBlocks[i].lpCompSurface == NULL)
|
|
{
|
|
for (j = 0; j < i; j++)
|
|
{
|
|
DEC_EXCLUSIVE_REF_CNT(((LPBYTE)(pMacroBlocks[i].lpCompSurface) - sizeof(DD_OBJECT)));
|
|
}
|
|
MmUnsecureVirtualMemory(hSecure);
|
|
hSecure = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if( (( pMacroBlocks == NULL ) && (dwNumMacroBlocks == 0)) ||
|
|
hSecure )
|
|
{
|
|
HANDLE hInputSecure = 0;
|
|
HANDLE hOutputSecure = 0;
|
|
|
|
// Secure the input buffer
|
|
cjInputData = RenderMoCompData.dwInputDataSize;
|
|
cjOutputData = RenderMoCompData.dwOutputDataSize;
|
|
if( puInputData )
|
|
{
|
|
__try
|
|
{
|
|
ProbeForWrite(puInputData, cjInputData, sizeof(UCHAR));
|
|
|
|
hInputSecure = MmSecureVirtualMemory(puInputData,
|
|
cjInputData,
|
|
PAGE_READWRITE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
|
|
// Secure the output buffer
|
|
if( puOutputData )
|
|
{
|
|
__try
|
|
{
|
|
ProbeForWrite(puOutputData, cjOutputData, sizeof(UCHAR));
|
|
|
|
hOutputSecure = MmSecureVirtualMemory(puOutputData,
|
|
cjOutputData,
|
|
PAGE_READWRITE);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
}
|
|
if( ( ( puInputData == NULL ) || hInputSecure ) &&
|
|
( ( puOutputData == NULL ) || hOutputSecure ) )
|
|
{
|
|
RenderMoCompData.lpInputData = puInputData;
|
|
RenderMoCompData.lpOutputData = puOutputData;
|
|
RenderMoCompData.lpBufferInfo = pMacroBlocks;
|
|
|
|
dwRet = peDirectDrawGlobal->MotionCompCallbacks.
|
|
RenderMoComp(&RenderMoCompData);
|
|
if (RenderMoCompData.ddRVal != DD_OK)
|
|
{
|
|
WARNING("DxDdEnderMoComp: Driver failed call\n");
|
|
}
|
|
}
|
|
|
|
if( hInputSecure )
|
|
{
|
|
MmUnsecureVirtualMemory(hInputSecure);
|
|
}
|
|
if( hOutputSecure )
|
|
{
|
|
MmUnsecureVirtualMemory(hOutputSecure);
|
|
}
|
|
}
|
|
|
|
if( hSecure )
|
|
{
|
|
for (i = 0; i < dwNumMacroBlocks; i++)
|
|
{
|
|
DEC_EXCLUSIVE_REF_CNT(((LPBYTE)(pMacroBlocks[i].lpCompSurface) - sizeof(DD_OBJECT)));
|
|
}
|
|
MmUnsecureVirtualMemory(hSecure);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdRenderMoComp: 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(&puRenderMoCompData->ddRVal,
|
|
RenderMoCompData.ddRVal);
|
|
ProbeAndWriteUlong(&puRenderMoCompData->dwOutputDataSize,
|
|
RenderMoCompData.dwOutputDataSize);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdQueryMoCompStatus
|
|
*
|
|
* 18-Nov-1997 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdQueryMoCompStatus(
|
|
HANDLE hMoComp,
|
|
PDD_QUERYMOCOMPSTATUSDATA puQueryMoCompStatusData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_QUERYMOCOMPSTATUSDATA QueryMoCompData;
|
|
|
|
__try
|
|
{
|
|
QueryMoCompData
|
|
= ProbeAndReadStructure(puQueryMoCompStatusData,
|
|
DD_QUERYMOCOMPSTATUSDATA);
|
|
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
QueryMoCompData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_MOTIONCOMP* peMotionComp;
|
|
EDD_LOCK_MOTIONCOMP eLockMotionComp;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
EDD_SURFACE* peSurface;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
|
|
peMotionComp = eLockMotionComp.peLock(hMoComp);
|
|
peSurface = eLockSurface.peLock(QueryMoCompData.lpSurface);
|
|
if ((peMotionComp != NULL) && (peSurface != NULL))
|
|
{
|
|
peDirectDrawGlobal = peMotionComp->peDirectDrawGlobal;
|
|
|
|
QueryMoCompData.lpDD = peDirectDrawGlobal;
|
|
QueryMoCompData.lpMoComp = peMotionComp;
|
|
QueryMoCompData.lpSurface = peSurface;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
if ((!peDirectDrawGlobal->bSuspended) &&
|
|
(peDirectDrawGlobal->MotionCompCallbacks.QueryMoCompStatus))
|
|
{
|
|
dwRet = peDirectDrawGlobal->MotionCompCallbacks.
|
|
QueryMoCompStatus(&QueryMoCompData);
|
|
if (QueryMoCompData.ddRVal != DD_OK)
|
|
{
|
|
WARNING("DxDdQueryMoCompStatus: Driver failed call\n");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdQueryMoCompStatus: 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(&puQueryMoCompStatusData->ddRVal,
|
|
QueryMoCompData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDdAlphaBlt
|
|
*
|
|
* 24-Nov-1997 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdAlphaBlt(
|
|
HANDLE hSurfaceDest,
|
|
HANDLE hSurfaceSrc,
|
|
PDD_BLTDATA puBltData
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DD_BLTDATA BltData;
|
|
|
|
__try
|
|
{
|
|
BltData
|
|
= ProbeAndReadStructure(puBltData,
|
|
DD_BLTDATA);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return(DDHAL_DRIVER_NOTHANDLED);
|
|
}
|
|
|
|
dwRet = DDHAL_DRIVER_NOTHANDLED;
|
|
BltData.ddRVal = DDERR_GENERIC;
|
|
|
|
EDD_SURFACE* peSurfaceDest;
|
|
EDD_SURFACE* peSurfaceSrc;
|
|
EDD_LOCK_SURFACE eLockSurfaceDest;
|
|
EDD_LOCK_SURFACE eLockSurfaceSrc;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peSurfaceDest = eLockSurfaceDest.peLock(hSurfaceDest);
|
|
BltData.lpDDDestSurface = peSurfaceDest;
|
|
|
|
if (peSurfaceDest != NULL)
|
|
{
|
|
peDirectDrawGlobal = peSurfaceDest->peDirectDrawGlobal;
|
|
if( peDirectDrawGlobal->flDriverInfo & DD_DRIVERINFO_MORECAPS )
|
|
{
|
|
// We support only a specific set of Blt calls down to the driver
|
|
// that we're willing to support and to test.
|
|
|
|
if (hSurfaceSrc == NULL)
|
|
{
|
|
// Do simpler stuff 'cause we don't need to lock a source:
|
|
|
|
BltData.lpDDSrcSurface = NULL;
|
|
peSurfaceSrc = NULL;
|
|
|
|
if ((peSurfaceDest->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) &&
|
|
(peDirectDrawGlobal->MoreCaps.dwVSBAlphaCaps == 0) &&
|
|
(peDirectDrawGlobal->MoreCaps.dwSSBAlphaCaps == 0))
|
|
{
|
|
WARNING("DxDdAlphaBlt: Can't blt to system memory surface");
|
|
return(dwRet);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Lock the source surface:
|
|
|
|
peSurfaceSrc = eLockSurfaceSrc.peLock(hSurfaceSrc);
|
|
BltData.lpDDSrcSurface = peSurfaceSrc;
|
|
|
|
// Ensure that both surfaces belong to the same DirectDraw
|
|
// object, and check source rectangle:
|
|
|
|
if ((peSurfaceSrc == NULL) ||
|
|
(peSurfaceSrc->peDirectDrawLocal !=
|
|
peSurfaceDest->peDirectDrawLocal) ||
|
|
(BltData.rSrc.left < 0) ||
|
|
(BltData.rSrc.top < 0) ||
|
|
(BltData.rSrc.right > (LONG) peSurfaceSrc->wWidth) ||
|
|
(BltData.rSrc.bottom > (LONG) peSurfaceSrc->wHeight) ||
|
|
(BltData.rSrc.left >= BltData.rSrc.right) ||
|
|
(BltData.rSrc.top >= BltData.rSrc.bottom))
|
|
{
|
|
WARNING("DxDdAlphaBlt: Invalid source surface or source rectangle\n");
|
|
return(dwRet);
|
|
}
|
|
|
|
if (peSurfaceDest->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
if (peSurfaceSrc->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
if (peDirectDrawGlobal->MoreCaps.dwSSBAlphaCaps == 0)
|
|
{
|
|
WARNING("DxDdAlphaBlt: System to System Blts not supported\n");
|
|
return(dwRet);
|
|
}
|
|
}
|
|
else if (peDirectDrawGlobal->MoreCaps.dwVSBAlphaCaps == 0)
|
|
{
|
|
WARNING("DxDdAlphaBlt: Video to System Blts not supported\n");
|
|
return(dwRet);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (peSurfaceSrc->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
if (peDirectDrawGlobal->MoreCaps.dwSVBAlphaCaps == 0)
|
|
{
|
|
WARNING("DxDdAlphaBlt: System to Video Blts not supported\n");
|
|
return(dwRet);
|
|
}
|
|
}
|
|
else if (peDirectDrawGlobal->MoreCaps.dwAlphaCaps == 0)
|
|
{
|
|
WARNING("DxDdAlphaBlt: Video to Video Blts not supported\n");
|
|
return(dwRet);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make sure that we weren't given rectangle coordinates
|
|
// which might cause the driver to crash. Note that we
|
|
// don't allow inverting stretch blts:
|
|
|
|
if ((BltData.rDest.left >= 0) &&
|
|
(BltData.rDest.top >= 0) &&
|
|
(BltData.rDest.right <= (LONG) peSurfaceDest->wWidth) &&
|
|
(BltData.rDest.bottom <= (LONG) peSurfaceDest->wHeight) &&
|
|
(BltData.rDest.left < BltData.rDest.right) &&
|
|
(BltData.rDest.top < BltData.rDest.bottom))
|
|
{
|
|
BltData.lpDD = peDirectDrawGlobal;
|
|
|
|
// Make sure that the surfaces aren't associated
|
|
// with a PDEV whose mode has gone away.
|
|
//
|
|
// Also ensure that there are no outstanding
|
|
// surface locks if running on a brain-dead video
|
|
// card that crashes if the accelerator runs at
|
|
// the same time the frame buffer is accessed.
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
// We will return SURFACELOST when ...
|
|
//
|
|
// 1) This device is suspended.
|
|
// 2) The driver managed surface is managed by other device.
|
|
// 3) One of surface is losted.
|
|
// 4) The visible region has been changed when surface is primary.
|
|
|
|
if (peDirectDrawGlobal->bSuspended) // 1)
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
BltData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else if ((peSurfaceDest->fl & DD_SURFACE_FLAG_WRONG_DRIVER) ||
|
|
((peSurfaceSrc != NULL) &&
|
|
(peSurfaceSrc->fl & DD_SURFACE_FLAG_WRONG_DRIVER))) // 2)
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
BltData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else if ((peSurfaceDest->bLost) ||
|
|
((peSurfaceSrc != NULL) && (peSurfaceSrc->bLost))) // 3)
|
|
{
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
BltData.ddRVal = DDERR_SURFACELOST;
|
|
}
|
|
else if ((peSurfaceDest->fl & DD_SURFACE_FLAG_PRIMARY) &&
|
|
(peSurfaceDest->iVisRgnUniqueness != VISRGN_UNIQUENESS())) // 4)
|
|
{
|
|
// The VisRgn changed since the application last queried it;
|
|
// fail the call with a unique error code so that they know
|
|
// to requery the VisRgn and try again:
|
|
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
BltData.ddRVal = DDERR_VISRGNCHANGED;
|
|
}
|
|
else
|
|
{
|
|
if (peDirectDrawGlobal->Miscellaneous2CallBacks.AlphaBlt)
|
|
{
|
|
DEVEXCLUDERECT dxo;
|
|
HANDLE hSecure;
|
|
ULONG cjData;
|
|
DWORD i;
|
|
LPRECT lpRect;
|
|
|
|
// Secure the clip list and ensure that all of its
|
|
// rectangles are valid
|
|
|
|
hSecure = 0;
|
|
if( BltData.dwRectCnt == 0 )
|
|
{
|
|
BltData.prDestRects = NULL;
|
|
}
|
|
else if ( BltData.prDestRects == NULL )
|
|
{
|
|
BltData.dwRectCnt = 0;
|
|
}
|
|
else
|
|
{
|
|
__try
|
|
{
|
|
cjData = BltData.dwRectCnt * sizeof( RECT );
|
|
if (!BALLOC_OVERFLOW1(BltData.dwRectCnt, RECT))
|
|
{
|
|
ProbeForWrite(BltData.prDestRects, cjData, sizeof(UCHAR));
|
|
|
|
hSecure = MmSecureVirtualMemory(BltData.prDestRects,
|
|
cjData,
|
|
PAGE_READWRITE);
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
if( hSecure == NULL )
|
|
{
|
|
BltData.ddRVal = DDERR_OUTOFMEMORY;
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
}
|
|
else
|
|
{
|
|
// Validate each rectangle
|
|
|
|
lpRect = BltData.prDestRects;
|
|
for( i = 0; i < BltData.dwRectCnt; i++ )
|
|
{
|
|
if ((lpRect->left < 0) ||
|
|
(lpRect->top < 0) ||
|
|
(lpRect->left > lpRect->right ) ||
|
|
(lpRect->top > lpRect->bottom ) )
|
|
{
|
|
MmUnsecureVirtualMemory(hSecure);
|
|
WARNING("DxDdAlphaBlt: Couldn't lock destination surface\n");
|
|
dwRet = DDHAL_DRIVER_HANDLED;
|
|
BltData.ddRVal = DDERR_INVALIDPARAMS;
|
|
break;
|
|
}
|
|
lpRect++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Only do the Blt it everything has worked up until now
|
|
|
|
if( dwRet == DDHAL_DRIVER_NOTHANDLED )
|
|
{
|
|
// Exclude the mouse pointer if necessary:
|
|
|
|
if (peSurfaceDest->fl & DD_SURFACE_FLAG_PRIMARY)
|
|
{
|
|
dxo.vExclude(peDirectDrawGlobal->hdev,
|
|
&BltData.rDest);
|
|
}
|
|
|
|
dwRet = peDirectDrawGlobal->Miscellaneous2CallBacks.
|
|
AlphaBlt(&BltData);
|
|
|
|
if( hSecure )
|
|
{
|
|
MmUnsecureVirtualMemory(hSecure);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdAlphaBlt: Invalid destination rectangle\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdAlphaBlt: Alpha not supported\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdAlphaBlt: Couldn't lock destination surface\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(&puBltData->ddRVal, BltData.ddRVal);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
return(dwRet);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DxDdSetGammaRamp
|
|
*
|
|
* The reason we need this function when GDI already has one is that
|
|
* DirectDraw games need the ability to set bizarre gamma ramps to
|
|
* achieve special effects. The GDI SetDeviceGammaRamp call does a range
|
|
* check that will reject all of these gamma ramps. When this function is
|
|
* used, DirectDraw gaurentees that the original gamma ramp gets restored
|
|
* when the game gets minimized or exits.
|
|
*
|
|
* History:
|
|
*
|
|
* Wrote it:
|
|
* 06-Jun-1998 -by- Scott MacDonald [smac]
|
|
\**************************************************************************/
|
|
|
|
#define MAX_COLORTABLE 256
|
|
|
|
BOOL
|
|
DxDdSetGammaRamp(
|
|
HANDLE hDirectDraw,
|
|
HDC hdc,
|
|
LPVOID lpGammaRamp
|
|
)
|
|
{
|
|
WORD * pTemp1;
|
|
WORD * pTemp2;
|
|
int i;
|
|
|
|
BOOL bRet = FALSE;
|
|
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
|
|
if (peDirectDrawLocal != NULL)
|
|
{
|
|
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
if (lpGammaRamp)
|
|
{
|
|
HANDLE hSecure = NULL;
|
|
BOOL bError = FALSE;
|
|
|
|
__try
|
|
{
|
|
ProbeForRead(lpGammaRamp, MAX_COLORTABLE * sizeof(WORD) * 3, sizeof(BYTE));
|
|
hSecure = MmSecureVirtualMemory(lpGammaRamp, MAX_COLORTABLE * sizeof(WORD) * 3, PAGE_READONLY);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("DxDdSetGammaRamp: Fail to capture usermode buffer\n");
|
|
bError = TRUE;
|
|
}
|
|
|
|
{
|
|
EDD_SHAREDEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
// If the gamma has not already been set by this app, get the existing gamma
|
|
// ramp and save it so we can clean up after ourselves.
|
|
|
|
if ((peDirectDrawLocal->pGammaRamp == NULL) && !bError)
|
|
{
|
|
peDirectDrawLocal->pGammaRamp = (WORD *) PALLOCMEM(MAX_COLORTABLE * 3 * sizeof(WORD), 'pddG');
|
|
if (peDirectDrawLocal->pGammaRamp != NULL)
|
|
{
|
|
bRet = DxEngGetDeviceGammaRamp( peDirectDrawGlobal->hdev, peDirectDrawLocal->pGammaRamp );
|
|
if (!bRet)
|
|
{
|
|
bError = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bError = TRUE;
|
|
}
|
|
}
|
|
|
|
// If this new gamma ramp is the same as the original ramp, we know
|
|
// that we are restoring it.
|
|
|
|
if ((peDirectDrawLocal->pGammaRamp != NULL) && !bError)
|
|
{
|
|
pTemp1 = (WORD *) lpGammaRamp;
|
|
pTemp2 = peDirectDrawLocal->pGammaRamp;
|
|
for (i = 0; i < MAX_COLORTABLE * 3; i++)
|
|
{
|
|
if (*pTemp1++ != *pTemp2++)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i == MAX_COLORTABLE * 3)
|
|
{
|
|
VFREEMEM(peDirectDrawLocal->pGammaRamp);
|
|
peDirectDrawLocal->pGammaRamp = NULL;
|
|
}
|
|
}
|
|
|
|
if ((bError == FALSE) && hSecure)
|
|
{
|
|
bRet = DxEngSetDeviceGammaRamp(peDirectDrawGlobal->hdev, lpGammaRamp, FALSE);
|
|
}
|
|
}
|
|
|
|
if (hSecure)
|
|
{
|
|
MmUnsecureVirtualMemory(hSecure);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DxDdSetGammaRamp: Invalid DirectDraw object specified\n");
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DxDdCreateSurfaceEx
|
|
*
|
|
* Just notify driver of new handle association by calling its
|
|
* CreateSurfaceEx
|
|
*
|
|
* History:
|
|
*
|
|
* Wrote it:
|
|
* 25-Feb-1999 -by- Kan Qiu [kanqiu]
|
|
\**************************************************************************/
|
|
|
|
DWORD
|
|
APIENTRY
|
|
DxDdCreateSurfaceEx(
|
|
HANDLE hDirectDraw,
|
|
HANDLE hSurface,
|
|
DWORD dwSurfaceHandle
|
|
)
|
|
{
|
|
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
|
|
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
|
|
EDD_SURFACE* peSurface;
|
|
EDD_LOCK_SURFACE eLockSurface;
|
|
|
|
peSurface = eLockSurface.peLock( hSurface );
|
|
|
|
if (peSurface == NULL)
|
|
{
|
|
WARNING("DxDdCreateSurfaceEx: Invalid surfaces specified\n");
|
|
return DDERR_GENERIC;
|
|
}
|
|
|
|
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
|
|
if (peDirectDrawLocal != NULL )
|
|
{
|
|
EDD_DIRECTDRAW_GLOBAL *peDirectDrawGlobal =
|
|
peDirectDrawLocal->peDirectDrawGlobal;
|
|
|
|
EDD_DEVLOCK eDevlock(peDirectDrawGlobal);
|
|
|
|
// associate user mode surface handle to kernel mode surface
|
|
|
|
if ((peSurface->dwSurfaceHandle != 0) &&
|
|
(peSurface->dwSurfaceHandle != dwSurfaceHandle))
|
|
{
|
|
WARNING("DxDdCreateSurfaceEx: called with surface which has been called already\n");
|
|
}
|
|
|
|
if (peDirectDrawGlobal->bSuspended)
|
|
{
|
|
return DDERR_SURFACELOST;
|
|
}
|
|
else if ((peDirectDrawGlobal->Miscellaneous2CallBacks.CreateSurfaceEx) &&
|
|
(dwSurfaceHandle != 0))
|
|
{
|
|
peSurface->dwSurfaceHandle = dwSurfaceHandle;
|
|
|
|
DD_CREATESURFACEEXDATA CreateSurfaceExData;
|
|
|
|
// Use the CreateSurfaceEx DDI to once again inform the
|
|
// driver that something has changed
|
|
CreateSurfaceExData.dwFlags = 0;
|
|
CreateSurfaceExData.ddRVal = DDERR_GENERIC;
|
|
CreateSurfaceExData.lpDDLcl = peDirectDrawLocal;
|
|
CreateSurfaceExData.lpDDSLcl = peSurface;
|
|
|
|
peDirectDrawGlobal->Miscellaneous2CallBacks.CreateSurfaceEx(&CreateSurfaceExData);
|
|
if (CreateSurfaceExData.ddRVal != DD_OK)
|
|
{
|
|
WARNING("DxDdCreateSurfaceEx: DDI call to the driver failed\n");
|
|
return (CreateSurfaceExData.ddRVal);
|
|
}
|
|
else
|
|
{
|
|
if (peSurface->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
|
|
{
|
|
PDEVOBJ po(peDirectDrawGlobal->hdev);
|
|
|
|
// Mark we called CreateSurfaceEx on this surface.
|
|
// this information will be used when we need to call
|
|
// CreateSurfaceEx after video mode change.
|
|
peSurface->fl |= DD_SURFACE_FLAG_SYSMEM_CREATESURFACEEX;
|
|
|
|
ASSERTGDI(peSurface->pGraphicsDeviceCreator == po.pGraphicsDevice(),
|
|
"DXG: CreateSurfaceEx: calling non-owner driver");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return DDERR_GENERIC;
|
|
}
|
|
}
|
|
return DD_OK;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DxDdCloseProcess
|
|
*
|
|
* 2-May-2000 -by- Hideyuki Nagase [hideyukn]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID DxDdCloseProcess(W32PID w32Pid)
|
|
{
|
|
DdHmgCloseProcess(w32Pid);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* PVOID DxDdAllocPrivateUserMem()
|
|
*
|
|
* History:
|
|
* 28-Oct-1999 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
PVOID
|
|
DxDdAllocPrivateUserMem(
|
|
PDD_SURFACE_LOCAL pSurfaceLocal,
|
|
SIZE_T cj, //ZwAllocateVirtualMemory uses SIZE_T, change accordingly
|
|
ULONG tag
|
|
)
|
|
{
|
|
EDD_SURFACE *peSurface = (EDD_SURFACE *) pSurfaceLocal;
|
|
PVOID pv = NULL;
|
|
|
|
//
|
|
// DirectDraw can call the driver outside of it's process (e.g. switching
|
|
// desktops, etc.), so this function helps protect against that.
|
|
//
|
|
|
|
if (PsGetCurrentProcess() == peSurface->peDirectDrawLocal->Process)
|
|
{
|
|
pv = EngAllocUserMem ( cj, tag );
|
|
}
|
|
|
|
return pv;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DxDdFreePrivateUserMem()
|
|
*
|
|
* History:
|
|
* 28-Oct-1999 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
DxDdFreePrivateUserMem(
|
|
PDD_SURFACE_LOCAL pSurfaceLocal,
|
|
PVOID pv
|
|
)
|
|
{
|
|
EDD_SURFACE *peSurface = (EDD_SURFACE *) pSurfaceLocal;
|
|
|
|
// If the surface has an aliased lock on it, then we don't want
|
|
// to delete this memory now or else the app may fault, so we put
|
|
// it in a list of memory to free later.
|
|
|
|
if (peSurface->fl & DD_SURFACE_FLAG_ALIAS_LOCK)
|
|
{
|
|
DeferMemoryFree(pv, peSurface);
|
|
}
|
|
else
|
|
{
|
|
SafeFreeUserMem(pv, peSurface->peDirectDrawLocal->Process);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DxDdIoctl()
|
|
*
|
|
* History:
|
|
* 17-Apr-2001 -by- Scott MacDonald [smac]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HRESULT
|
|
DxDdIoctl(
|
|
ULONG Ioctl,
|
|
PVOID pBuffer,
|
|
ULONG BufferSize
|
|
)
|
|
{
|
|
return DDERR_UNSUPPORTED;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* DxDdLock/UnlockDirectDrawSurface
|
|
*
|
|
* Functions to allow drivers to lock and unlock DirectDraw surface handles
|
|
* that may get passed to them.
|
|
*
|
|
* Such handles are currently passed to the driver in the Direct3D texture
|
|
* interface, necessitating these functions.
|
|
*
|
|
* History:
|
|
* Wed Oct 23 15:52:27 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
PDD_SURFACE_LOCAL
|
|
DxDdLockDirectDrawSurface(HANDLE hSurface)
|
|
{
|
|
EDD_SURFACE *peSurf;
|
|
|
|
peSurf = (EDD_SURFACE *)DdHmgLock((HDD_OBJ)hSurface, DD_SURFACE_TYPE, FALSE);
|
|
if (peSurf != NULL)
|
|
{
|
|
return (PDD_SURFACE_LOCAL)peSurf;
|
|
}
|
|
else
|
|
{
|
|
return peSurf;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
DxDdUnlockDirectDrawSurface(PDD_SURFACE_LOCAL pSurface)
|
|
{
|
|
if (pSurface != NULL)
|
|
{
|
|
DEC_EXCLUSIVE_REF_CNT((EDD_SURFACE *)pSurface);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DxDdEnableDirectDrawRedirection
|
|
*
|
|
* 11-Apr-2000 -by- Hideyuki Nagase [hideyukn]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL DxDdEnableDirectDrawRedirection(HDEV hdev, BOOL bEnable)
|
|
{
|
|
#ifdef DX_REDIRECTION
|
|
LONG* pl;
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
if (po.bValid())
|
|
{
|
|
// Hold devlock to prevent from mode change.
|
|
|
|
EDD_DEVLOCK eDevLock(po.hdev());
|
|
|
|
// Bump the mode uniqueness to let user-mode DirectDraw know that
|
|
// someone else has done 'something' need to refresh user-mode
|
|
// data.
|
|
|
|
INC_DISPLAY_UNIQUENESS();
|
|
|
|
// Save redirection status
|
|
|
|
gbDxRedirection = bEnable;
|
|
|
|
return (TRUE);
|
|
}
|
|
else
|
|
{
|
|
return (FALSE);
|
|
}
|
|
#else
|
|
return (FALSE);
|
|
#endif // DX_REDIRECTION
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DxDdSetAccelLevel
|
|
*
|
|
* 2-Oct-2000 -by- Hideyuki Nagase [hideyukn]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID DxDdSetAccelLevel(HDEV hdev, DWORD dwAccelLevel, DWORD dwOverride)
|
|
{
|
|
if ((dwAccelLevel >= 3) ||
|
|
(dwOverride & DRIVER_NOT_CAPABLE_DDRAW))
|
|
{
|
|
PDEVOBJ po(hdev);
|
|
|
|
po.peDirectDrawGlobal()->llAssertModeTimeout = 0;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DxDdGetSurfaceLock
|
|
*
|
|
* 2-Oct-2000 -by- Hideyuki Nagase [hideyukn]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD DxDdGetSurfaceLock(HDEV hdev)
|
|
{
|
|
PDEVOBJ po(hdev);
|
|
|
|
return (po.peDirectDrawGlobal()->cSurfaceLocks);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID DxDdEnumLockedSurfaceRect
|
|
*
|
|
* 2-Oct-2000 -by- Hideyuki Nagase [hideyukn]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
PVOID DxDdEnumLockedSurfaceRect(HDEV hdev, PVOID pvSurface, RECTL *pRect)
|
|
{
|
|
PDEVOBJ po(hdev);
|
|
|
|
EDD_SURFACE *peSurface;
|
|
|
|
if (pvSurface == NULL)
|
|
{
|
|
peSurface = po.peDirectDrawGlobal()->peSurface_PrimaryLockList;
|
|
}
|
|
else
|
|
{
|
|
peSurface = ((EDD_SURFACE *)pvSurface)->peSurface_PrimaryLockNext;
|
|
}
|
|
|
|
if (peSurface)
|
|
{
|
|
*pRect = peSurface->rclLock;
|
|
}
|
|
|
|
return ((PVOID)peSurface);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD DxDxgGenericThunk
|
|
*
|
|
* 14-Jun-2000 -by- Hideyuki Nagase [hideyukn]
|
|
* Wrote it (stub).
|
|
\**************************************************************************/
|
|
|
|
DWORD DxDxgGenericThunk(
|
|
IN ULONG_PTR ulIndex,
|
|
IN ULONG_PTR ulHandle,
|
|
IN OUT SIZE_T *pdwSizeOfPtr1,
|
|
IN OUT PVOID pvPtr1,
|
|
IN OUT SIZE_T *pdwSizeOfPtr2,
|
|
IN OUT PVOID pvPtr2)
|
|
{
|
|
UNREFERENCED_PARAMETER(ulIndex);
|
|
UNREFERENCED_PARAMETER(ulHandle);
|
|
UNREFERENCED_PARAMETER(pdwSizeOfPtr1);
|
|
UNREFERENCED_PARAMETER(pvPtr1);
|
|
UNREFERENCED_PARAMETER(pdwSizeOfPtr2);
|
|
UNREFERENCED_PARAMETER(pvPtr2);
|
|
|
|
return (0);
|
|
}
|