Leaked source code of windows server 2003
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

/******************************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);
}