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