Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5648 lines
182 KiB

/******************************Module*Header*******************************\
* Module Name: ddraw.cxx
*
* Contains all of GDI's private DirectDraw APIs.
*
* Created: 3-Dec-1995
* Author: J. Andrew Goossen [andrewgo]
*
* Copyright (c) 1995-1996 Microsoft Corporation
*
\**************************************************************************/
#include "precomp.hxx"
extern "C"
{
#include <ntddvdeo.h>
}
// The following is a global uniqueness that gets bumped up anytime USER
// changes anyone's VisRgn:
ULONG giVisRgnUniqueness = 0;
// 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;
/******************************Public*Routine******************************\
* VOID vDdAssertDevlock
*
* Debug code for verifying that the devlock is currently held.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#if DBG
VOID
vDdAssertDevlock(
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
)
{
PDEVOBJ po(peDirectDrawGlobal->hdev);
ASSERTGDI(po.pDevLock()->OwnerThreads[0].OwnerThread
== (ERESOURCE_THREAD) PsGetCurrentThread(),
"DD_ASSERTDEVLOCK failed");
}
#endif
/******************************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.
\**************************************************************************/
#if DBG
VOID
vDdAssertNoDevlock(
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
)
{
PDEVOBJ po(peDirectDrawGlobal->hdev);
ASSERTGDI(po.pDevLock()->OwnerThreads[0].OwnerThread
!= (ERESOURCE_THREAD) PsGetCurrentThread(),
"DD_ASSERTNODEVLOCK failed");
}
#endif
/******************************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(
PDEVOBJ& po,
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
)
{
BOOL b;
DDCAPS* pCaps;
b = TRUE;
if (po.iDitherFormat() < BMF_8BPP)
{
WARNING("DirectDraw not supported at display depths less than 8bpp\n");
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_3D
| DDCAPS_GDI
| DDCAPS_PALETTE
| DDCAPS_STEREOVIEW
| DDCAPS_ZBLTS
| DDCAPS_ZOVERLAYS
| DDCAPS_BANKSWITCHED
| DDCAPS_BLTDEPTHFILL
| DDCAPS_CANBLTSYSMEM))
{
RIP("HalInfo.ddCaps.dwCaps has capabilities set that aren't supported by NT\n");
b = FALSE;
}
if (pCaps->ddsCaps.dwCaps & ~(DDSCAPS_OFFSCREENPLAIN
| DDSCAPS_PRIMARYSURFACE
| DDSCAPS_FLIP
| DDSCAPS_OVERLAY
| DDSCAPS_MODEX))
{
RIP("HalInfo.ddCaps.ddsCaps.dwCaps has capabilities set that aren't supported by NT\n");
b = FALSE;
}
if (pCaps->dwFXCaps & (DDFXCAPS_BLTMIRRORLEFTRIGHT
| DDFXCAPS_BLTMIRRORUPDOWN
| DDFXCAPS_BLTROTATION
| DDFXCAPS_BLTROTATION90))
{
RIP("HalInfo.ddCaps.dwFXCaps has capabilities set that aren't supported by NT\n");
b = FALSE;
}
if (pCaps->dwFXAlphaCaps != 0)
{
RIP("HalInfo.ddCaps.dwFXAlphaCaps has capabilities set that aren't supported by NT\n");
b = FALSE;
}
if (pCaps->dwPalCaps != 0)
{
RIP("HalInfo.ddCaps.dwPalCaps has capabilities set that aren't supported by NT\n");
b = FALSE;
}
if (pCaps->dwSVCaps != 0)
{
RIP("HalInfo.ddCaps.dwSVCaps has capabilities set that aren't supported by NT\n");
b = FALSE;
}
return(b);
}
/******************************Public*Routine******************************\
* BOOL bDdEnableDriver
*
* 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.
\**************************************************************************/
BOOL
bDdEnableDriver(
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
)
{
BOOL bSuccess;
PFN_DrvGetDirectDrawInfo pfnGetDirectDrawInfo;
PFN_DrvEnableDirectDraw pfnEnableDirectDraw;
PFN_DrvDisableDirectDraw pfnDisableDirectDraw;
DWORD dwNumHeaps;
DWORD dwNumFourCC;
VIDEOMEMORY* pvmList;
DWORD* pdwFourCC;
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
ASSERTGDI(!(peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_DRIVER_ENABLED),
"Trying to enable driver when already enabled");
PDEVOBJ po(peDirectDrawGlobal->hdev);
pfnGetDirectDrawInfo = PPFNDRV(po, GetDirectDrawInfo);
pfnEnableDirectDraw = PPFNDRV(po, EnableDirectDraw);
pfnDisableDirectDraw = PPFNDRV(po, DisableDirectDraw);
if ((pfnGetDirectDrawInfo == NULL) ||
(pfnEnableDirectDraw == NULL) ||
(pfnDisableDirectDraw == NULL))
{
// To support DirectDraw, the driver must hook all three required
// DirectDraw functions.
return(FALSE);
}
// Zero all the structures if we're re-enabling the driver:
RtlZeroMemory(&peDirectDrawGlobal->HalInfo,
sizeof(peDirectDrawGlobal->HalInfo));
RtlZeroMemory(&peDirectDrawGlobal->CallBacks,
sizeof(peDirectDrawGlobal->CallBacks));
RtlZeroMemory(&peDirectDrawGlobal->SurfaceCallBacks,
sizeof(peDirectDrawGlobal->SurfaceCallBacks));
RtlZeroMemory(&peDirectDrawGlobal->PaletteCallBacks,
sizeof(peDirectDrawGlobal->PaletteCallBacks));
peDirectDrawGlobal->dwNumHeaps = 0;
peDirectDrawGlobal->dwNumFourCC = 0;
dwNumHeaps = 0;
dwNumFourCC = 0;
// 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 (pfnGetDirectDrawInfo((DHPDEV) peDirectDrawGlobal->dhpdev,
&peDirectDrawGlobal->HalInfo,
&dwNumHeaps,
NULL,
&dwNumFourCC,
NULL))
{
bSuccess = TRUE;
pvmList = NULL;
pdwFourCC = NULL;
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 (((ULONG) peDirectDrawGlobal->HalInfo.vmiData.pvPrimary
> MM_USER_PROBE_ADDRESS) ||
(peDirectDrawGlobal->HalInfo.vmiData.fpPrimary
== DDHAL_PLEASEALLOC_USERMEM))
{
if (pfnEnableDirectDraw((DHPDEV) peDirectDrawGlobal->dhpdev,
&peDirectDrawGlobal->CallBacks,
&peDirectDrawGlobal->SurfaceCallBacks,
&peDirectDrawGlobal->PaletteCallBacks))
{
if (bDdValidateDriverData(po, peDirectDrawGlobal))
{
peDirectDrawGlobal->fl |= DD_GLOBAL_FLAG_DRIVER_ENABLED;
return(TRUE);
}
pfnDisableDirectDraw((DHPDEV) peDirectDrawGlobal->dhpdev);
}
}
else
{
WARNING("bDdEnableDriver: Driver returned invalid vmiData.pvPrimary\n");
}
}
}
if (pvmList != NULL)
VFREEMEM(pvmList);
if (pdwFourCC != NULL)
VFREEMEM(pdwFourCC);
}
return(FALSE);
}
/******************************Public*Routine******************************\
* VOID vDdDisableDriver
*
* Assumes devlock already held.
*
* It is the caller's responsibility to ensure that the driver is actually
* enabled. (Which may not be the case if the application has not called
* ReenableDirectDrawObject yet.)
*
* Note: This function may be called before the surface is 'completed'!
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
vDdDisableDriver(
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
)
{
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
ASSERTGDI(peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_DRIVER_ENABLED,
"Trying to disable driver when not enabled");
peDirectDrawGlobal->fl &= ~DD_GLOBAL_FLAG_DRIVER_ENABLED;
PDEVOBJ po(peDirectDrawGlobal->hdev);
(*PPFNDRV(po, DisableDirectDraw))((DHPDEV) peDirectDrawGlobal->dhpdev);
if (peDirectDrawGlobal->pvmList != NULL)
{
VFREEMEM(peDirectDrawGlobal->pvmList);
peDirectDrawGlobal->pvmList = NULL;
}
if (peDirectDrawGlobal->pdwFourCC != NULL)
{
VFREEMEM(peDirectDrawGlobal->pdwFourCC);
peDirectDrawGlobal->pdwFourCC = NULL;
}
}
/******************************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;
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet\\"
L"Control\\GraphicsDrivers\\DCI");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
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);
}
ZwClose(hkRegistry);
}
return(llTimeout);
}
/******************************Public*Routine******************************\
* EDD_DIRECTDRAW_GLOBAL* peDdCreateDirectDrawGlobal
*
* 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.
\**************************************************************************/
EDD_DIRECTDRAW_GLOBAL*
peDdCreateDirectDrawGlobal(
PDEVOBJ& po
)
{
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
KEVENT* pAssertModeEvent;
NTSTATUS status;
// Note that this must be zero initialized, because we promised
// the driver that we would:
peDirectDrawGlobal = (EDD_DIRECTDRAW_GLOBAL*)
PALLOCMEM(sizeof(EDD_DIRECTDRAW_GLOBAL), 'dddG');
if (peDirectDrawGlobal != NULL)
{
// Initialize our private structures:
peDirectDrawGlobal->hdev = po.hdev();
peDirectDrawGlobal->llAssertModeTimeout = llDdAssertModeTimeout();
peDirectDrawGlobal->dhpdev = po.dhpdev();
// A timeout value of 'zero' signifies that DirectDraw accelerations
// cannot be enabled:
if (peDirectDrawGlobal->llAssertModeTimeout < 0)
{
// The event must live in non-paged pool:
pAssertModeEvent = (KEVENT*) ExAllocatePoolWithTag(NonPagedPool,
sizeof(KEVENT),
' ddG');
if (pAssertModeEvent != NULL)
{
peDirectDrawGlobal->pAssertModeEvent = pAssertModeEvent;
status = KeInitializeEvent(pAssertModeEvent,
SynchronizationEvent,
FALSE);
ASSERTGDI(NT_SUCCESS(status), "Event initialization failed\n");
peDirectDrawGlobal->bDisabled = TRUE;
if (po.cDirectDrawDisableLocks() == 0)
{
peDirectDrawGlobal->bDisabled
= !bDdEnableDriver(peDirectDrawGlobal);
}
po.peDirectDrawGlobal(peDirectDrawGlobal);
return(peDirectDrawGlobal);
}
}
else
{
WARNING("DirectDraw is disabled in the registry");
}
VFREEMEM(peDirectDrawGlobal);
}
return(NULL);
}
/******************************Public*Routine******************************\
* VOID vDdDeleteDirectDrawGlobal
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
vDdDeleteDirectDrawGlobal(
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal
)
{
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
PDEVOBJ po(peDirectDrawGlobal->hdev);
// We could be killing off the object between the time the driver has
// been disabled and re-enabled after a mode switch, so check the
// enabled status:
if (peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_DRIVER_ENABLED)
{
vDdDisableDriver(peDirectDrawGlobal);
}
ExFreePool(peDirectDrawGlobal->pAssertModeEvent);
if (peDirectDrawGlobal->prgnUnlocked != NULL)
{
peDirectDrawGlobal->prgnUnlocked->vDeleteREGION();
}
po.peDirectDrawGlobal(NULL);
VFREEMEM(peDirectDrawGlobal);
}
/******************************Public*Routine******************************\
* VOID vDdDisableDirectDrawObject
*
* Disables a DirectDraw object.
*
* 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;
DD_MAPMEMORYDATA MapMemoryData;
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
if (peDirectDrawLocal->fl & DD_LOCAL_FLAG_MEMORY_MAPPED)
{
peDirectDrawLocal->fl &= ~DD_LOCAL_FLAG_MEMORY_MAPPED;
// 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.
if (peDirectDrawGlobal->CallBacks.dwFlags & DDHAL_CB32_MAPMEMORY)
{
ClientId.UniqueThread = (HANDLE) NULL;
ClientId.UniqueProcess = peDirectDrawLocal->UniqueProcess;
InitializeObjectAttributes(&ObjectAttributes,
NULL,
OBJ_INHERIT,
NULL,
NULL);
Status = ZwOpenProcess(&ProcessHandle,
PROCESS_DUP_HANDLE,
&ObjectAttributes,
&ClientId);
if (NT_SUCCESS(Status))
{
MapMemoryData.lpDD = peDirectDrawGlobal;
MapMemoryData.bMap = FALSE;
MapMemoryData.hProcess = ProcessHandle;
MapMemoryData.fpProcess = peDirectDrawLocal->fpProcess;
peDirectDrawGlobal->CallBacks.MapMemory(&MapMemoryData);
ASSERTGDI(MapMemoryData.ddRVal == DD_OK,
"Driver failed DirectDraw memory unmap\n");
Status = ZwClose(ProcessHandle);
ASSERTGDI(NT_SUCCESS(Status), "Failed close handle");
}
else
{
WARNING("vDdDisableDirectDrawObject: Couldn't open process handle");
}
}
}
if (peDirectDrawLocal->fl & DD_LOCAL_FLAG_MODEX_ENABLED)
{
peDirectDrawGlobal->fl |= DD_GLOBAL_FLAG_MODE_CHANGED;
// Since the only object that owns ModeX is going away, we have to
// disable the ModeX driver before we actually disable ModeX:
if (peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_DRIVER_ENABLED)
{
vDdDisableDriver(peDirectDrawGlobal);
}
// All operations affecting the ModeX driver shouldd be done before
// vDdDisableModeX, because this resets the call tables to no
// longer point to the ModeX entries:
vDdDisableModeX(peDirectDrawLocal);
}
}
/******************************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;
// We allocate this via the handle manager so that we can use the
// existing handle manager process clean-up mechanisms:
h = 0;
peDirectDrawLocal = (EDD_DIRECTDRAW_LOCAL*) HmgAlloc(
sizeof(EDD_DIRECTDRAW_LOCAL),
DD_DIRECTDRAW_TYPE,
HMGR_ALLOC_LOCK);
if (peDirectDrawLocal != NULL)
{
peDirectDrawGlobal = po.peDirectDrawGlobal();
if (peDirectDrawGlobal == NULL)
{
peDirectDrawGlobal = peDdCreateDirectDrawGlobal(po);
if (peDirectDrawGlobal == NULL)
{
HmgFree((HOBJ) peDirectDrawLocal->hGet());
return(0);
}
}
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
// Insert this object at the head of the object list:
peDirectDrawLocal->peDirectDrawLocalNext
= peDirectDrawGlobal->peDirectDrawLocalList;
peDirectDrawGlobal->peDirectDrawLocalList = peDirectDrawLocal;
// Initialize private GDI data:
peDirectDrawLocal->peDirectDrawGlobal = peDirectDrawGlobal;
peDirectDrawLocal->UniqueProcess = PsGetCurrentThread()->Cid.UniqueProcess;
peDirectDrawLocal->Process = PsGetCurrentProcess();
// Do an HmgUnlock:
h = peDirectDrawLocal->hHmgr;
DEC_EXCLUSIVE_REF_CNT(peDirectDrawLocal);
}
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 bCleanUp
)
{
BOOL bRet;
BOOL b;
VOID* pRemove;
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
EDD_DIRECTDRAW_LOCAL* peTmp;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
EDD_SURFACE* peSurface;
EDD_SURFACE* peNext;
bRet = FALSE;
peDirectDrawLocal = (EDD_DIRECTDRAW_LOCAL*)
HmgLock((HOBJ) hDirectDrawLocal, DD_DIRECTDRAW_TYPE);
if (peDirectDrawLocal != NULL)
{
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
// First, try to delete all surfaces associated with this object:
b = TRUE;
for (peSurface = peDirectDrawLocal->peSurface_DdList;
peSurface != NULL;
peSurface = peNext)
{
// Don't reference peSurface after it's been deleted!
peNext = peSurface->peSurface_DdNext;
b &= bDdDeleteSurfaceObject(peSurface->hGet(), bCleanUp, NULL);
}
// Only delete the DirectDraw object if we successfully deleted
// all linked surface objects:
if (b)
{
// Remove object from the handle manager:
pRemove = HmgRemoveObject((HOBJ) hDirectDrawLocal,
1,
0,
TRUE,
DD_DIRECTDRAW_TYPE);
ASSERTGDI(pRemove != NULL, "Couldn't delete DirectDraw object");
vDdDisableDirectDrawObject(peDirectDrawLocal);
////////////////////////////////////////////////////////////
// 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;
}
if (peDirectDrawGlobal->peDirectDrawLocalList == NULL)
{
vDdDeleteDirectDrawGlobal(peDirectDrawGlobal);
}
// We're all done with this object, so free the memory and
// leave:
FREEOBJ(peDirectDrawLocal, DD_DIRECTDRAW_TYPE);
bRet = TRUE;
}
else
{
WARNING("bDdDeleteDirectDrawObject: A surface was busy\n");
}
VRELEASEDEVLOCK(po.pDevLock());
// 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******************************\
* REGION* prgnDdUnlockedRegion
*
* This returns a pointer to a region that describes the unlocked portions
* of the screen.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
REGION* prgnDdUnlockedRegion(
HDEV hdev
)
{
REGION* prgn;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
RECTL rcl;
EDD_SURFACE* peSurface;
PDEVOBJ po(hdev);
ASSERTGDI(po.bDisplayPDEV(), "Invalid HDEV");
prgn = NULL;
peDirectDrawGlobal = po.peDirectDrawGlobal();
if ((peDirectDrawGlobal != NULL) &&
(peDirectDrawGlobal->cSurfaceLocks != 0))
{
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
if (!(peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_UNLOCKED_REGION_INVALID) &&
(peDirectDrawGlobal->prgnUnlocked != NULL))
{
prgn = peDirectDrawGlobal->prgnUnlocked;
}
else
{
// Get rid of the old region:
if (peDirectDrawGlobal->prgnUnlocked != NULL)
{
peDirectDrawGlobal->prgnUnlocked->vDeleteREGION();
peDirectDrawGlobal->prgnUnlocked = NULL;
}
// Calculate the new region:
RGNMEMOBJ rmoUnlocked((BOOL) FALSE);
if (rmoUnlocked.bValid())
{
rcl.left = 0;
rcl.top = 0;
rcl.right = po.sizl().cx;
rcl.bottom = po.sizl().cy;
rmoUnlocked.vSet(&rcl);
RGNMEMOBJTMP rmoRect((BOOL) FALSE);
RGNMEMOBJTMP rmoTmp((BOOL) FALSE);
if (rmoRect.bValid() && rmoTmp.bValid())
{
// Loop through the list of locked surfaces and remove
// their locked rectangles from the inclusion region:
for (peSurface = peDirectDrawGlobal->peSurface_LockList;
peSurface != NULL;
peSurface = peSurface->peSurface_LockNext)
{
// We don't check the return codes on 'bCopy' and
// 'bMerge' because both guarantee that they will
// maintain valid region constructs -- even if the
// contents are incorrect. And if we fail here
// because we're low on memory, it's guaranteed that
// there will already be plenty of incorrect drawing,
// so we don't care if our inclusion region is
// invalid:
rmoRect.vSet(&peSurface->rclLock);
rmoTmp.bCopy(rmoUnlocked);
rmoUnlocked.bMerge(rmoTmp, rmoRect, gafjRgnOp[RGN_DIFF]);
}
}
prgn = rmoUnlocked.prgnGet();
peDirectDrawGlobal->prgnUnlocked = prgn;
peDirectDrawGlobal->fl
&= ~DD_GLOBAL_FLAG_UNLOCKED_REGION_INVALID;
}
}
}
return(prgn);
}
/******************************Public*Routine******************************\
* BOOL bDdPointerNeedsOccluding
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
bDdPointerNeedsOccluding(
HDEV hdev
)
{
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
RECTL rclPointer;
EDD_SURFACE* peTmp;
PDEVOBJ po(hdev);
peDirectDrawGlobal = po.peDirectDrawGlobal();
if (peDirectDrawGlobal != NULL)
{
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
rclPointer.left = po.ptlPointer().x + po.rclPointerOffset().left;
rclPointer.right = po.ptlPointer().x + po.rclPointerOffset().right;
rclPointer.top = po.ptlPointer().y + po.rclPointerOffset().top;
rclPointer.bottom = po.ptlPointer().y + po.rclPointerOffset().bottom;
for (peTmp = peDirectDrawGlobal->peSurface_LockList;
peTmp != NULL;
peTmp = peTmp->peSurface_LockNext)
{
if (bDdIntersect(&rclPointer, &peTmp->rclLock))
{
return(TRUE);
}
}
}
return(FALSE);
}
/******************************Public*Routine******************************\
* VOID vDdRelinquishSurfaceLock
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
vDdRelinquishSurfaceLock(
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 (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)
{
peDirectDrawGlobal->cSurfaceLocks--;
// 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_LockList == peSurface)
{
peDirectDrawGlobal->peSurface_LockList = peSurface->peSurface_LockNext;
}
else
{
for (peTmp = peDirectDrawGlobal->peSurface_LockList;
peTmp->peSurface_LockNext != peSurface;
peTmp = peTmp->peSurface_LockNext)
{
ASSERTGDI(peTmp != NULL, "Can't find surface in lock list");
}
peTmp->peSurface_LockNext = peSurface->peSurface_LockNext;
}
peSurface->peSurface_LockNext = NULL;
// Redraw the drag rectangle, if there is one. Note that this
// has to occur after the surface is removed from the lock list.
peDirectDrawGlobal->fl |= DD_GLOBAL_FLAG_UNLOCKED_REGION_INVALID;
if (po.bHaveDragRect())
{
bDrawDragRectangles(po, &peSurface->rclLock);
}
// If no outstanding surface locks can be found that intersect with
// the pointer, then we can redraw it:
if (po.bPtrDirectDrawOccluded() &&
!bDdPointerNeedsOccluding(peDirectDrawGlobal->hdev))
{
ASSERTGDI(!po.bDisabled(),
"Expected to always be called before PDEV disabled");
ASSERTGDI(po.bPtrNeedsExcluding(),
"Expected a DirectDraw occluded pointer to need exclusion");
ASSERTGDI(!po.bPtrHidden(),
"Expected a DirectDraw occluded pointer not to be hidden");
po.bPtrDirectDrawOccluded(FALSE);
po.pfnMove()(po.pSurface()->pSurfobj(),
po.ptlPointer().x,
po.ptlPointer().y,
&po.rclPointer());
}
}
}
}
/******************************Public*Routine******************************\
* VOID vDdDisableSurfaceObject
*
* Disables a kernel-mode representation of the surface.
*
* 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
)
{
HDC hdc;
DWORD dwRet;
DD_FLIPDATA FlipData;
EDD_SURFACE* peSurfaceCurrent;
EDD_SURFACE* peSurfacePrimary;
DD_DESTROYSURFACEDATA DestroySurfaceData;
DD_UPDATEOVERLAYDATA UpdateOverlayData;
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
ASSERTGDI(!(peSurface->bLost) ||
!(peSurface->fl & DD_SURFACE_FLAG_CREATE_COMPLETE),
"Surface already disabled");
peSurface->bLost = TRUE;
hdc = peSurface->hdc;
if (hdc)
{
// 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.
DCOBJA dco(hdc);
if (dco.bValid())
{
dco.bInFullScreen(TRUE);
}
else
{
WARNING("vDdDisableSurfaceObject: Couldn't find GetDC DC\n");
}
}
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;
KdPrint(("GDI vDdDisableSurfaceObject: Preemptorily unmapping application's\n"));
KdPrint((" frame buffer view at 0x%lx!\n\n", gfpUnmap));
}
// Remove any outstanding locks and repaint the mouse pointer:
while (peSurface->cLocks != 0)
{
vDdRelinquishSurfaceLock(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_MEM_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;
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))
{
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_MEM_ALLOCATED)
{
ASSERTGDI(peSurface->fpVidMem != NULL, "Expected non-NULL fpVidMem");
if (PsGetCurrentProcess() == peSurface->peDirectDrawLocal->Process)
{
EngFreeUserMem((VOID*) peSurface->fpVidMem);
}
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(&peSurface->peDirectDrawLocal->Process->Pcb);
EngFreeUserMem((VOID*) peSurface->fpVidMem);
KeDetachProcess();
}
peSurface->fpVidMem = 0;
}
// Mark the surface as complete so that no-one can try to complete
// a stale surface:
peSurface->fl |= DD_SURFACE_FLAG_CREATE_COMPLETE;
// 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.
dwRet = DDHAL_DRIVER_NOTHANDLED;
if ((peSurface->fl & DD_SURFACE_FLAG_DRIVER_CREATED) &&
(peDirectDrawGlobal->SurfaceCallBacks.dwFlags &
DDHAL_SURFCB32_DESTROYSURFACE))
{
DestroySurfaceData.lpDD = peDirectDrawGlobal;
DestroySurfaceData.lpDDSurface = peSurface;
dwRet = peDirectDrawGlobal->
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 PLEASE_ALLOC_USERMEM. We
// munged the return code for PLEASE_ALLOCUSERMEM at CreateSurface
// time; we have to munge it now, too:
if ((dwRet == DDHAL_DRIVER_NOTHANDLED) &&
(peSurface->fl & DD_SURFACE_FLAG_MEM_ALLOCATED))
{
dwRet = DDHAL_DRIVER_HANDLED;
}
}
if (pdwRet != NULL)
{
*pdwRet = dwRet;
}
}
/******************************Public*Routine******************************\
* BOOL bDdDeleteSurfaceObject
*
* Deletes a kernel-mode representation of the surface.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
bDdDeleteSurfaceObject(
HANDLE hSurface,
BOOL bCleanUp,
DWORD* pdwRet // For returning driver return code, may be NULL
)
{
BOOL bRet;
BOOL bRepaint;
EDD_SURFACE* peSurface;
EDD_SURFACE* peTmp;
VOID* pvRemove;
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
DWORD dwRet;
bRet = FALSE;
bRepaint = FALSE;
dwRet = DDHAL_DRIVER_NOTHANDLED;
peSurface = (EDD_SURFACE*) HmgLock((HOBJ) hSurface, DD_SURFACE_TYPE);
if (peSurface != NULL)
{
peDirectDrawLocal = peSurface->peDirectDrawLocal;
pvRemove = HmgRemoveObject((HOBJ) hSurface,
HmgQueryLock((HOBJ) hSurface),
0,
TRUE,
DD_SURFACE_TYPE);
ASSERTGDI(pvRemove != NULL, "Outstanding surfaces locks");
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
// 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->hdc)
{
bDeleteDCInternal(peSurface->hdc, TRUE, FALSE);
}
// Remove from the surface linked-list:
if (peDirectDrawLocal->peSurface_DdList == peSurface)
{
peDirectDrawLocal->peSurface_DdList = peSurface->peSurface_DdNext;
}
else
{
for (peTmp = peDirectDrawLocal->peSurface_DdList;
peTmp->peSurface_DdNext != peSurface;
peTmp = peTmp->peSurface_DdNext)
;
peTmp->peSurface_DdNext = peSurface->peSurface_DdNext;
}
VRELEASEDEVLOCK(po.pDevLock());
// We're all done with this object, so free the memory and
// leave:
FREEOBJ(peSurface, DD_SURFACE_TYPE);
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_SURFACE* peSurface;
NTSTATUS status;
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
PDEVOBJ po(peDirectDrawGlobal->hdev);
if (po.cDirectDrawDisableLocks() == 1)
{
peDirectDrawGlobal->bDisabled = TRUE;
if (peDirectDrawGlobal->cSurfaceLocks != 0)
{
// Release the devlock while waiting on the event:
VRELEASEDEVLOCK(po.pDevLock());
status = KeWaitForSingleObject(peDirectDrawGlobal->pAssertModeEvent,
Executive,
KernelMode,
FALSE,
(LARGE_INTEGER*) &peDirectDrawGlobal->
llAssertModeTimeout);
ASSERTGDI(NT_SUCCESS(status), "Wait error\n");
VACQUIREDEVLOCK(po.pDevLock());
// 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):
status = KeInitializeEvent(peDirectDrawGlobal->pAssertModeEvent,
SynchronizationEvent,
FALSE);
ASSERTGDI(NT_SUCCESS(status), "Event initialization failed\n");
}
}
// 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)
{
for (peSurface = peDirectDrawLocal->peSurface_DdList;
peSurface != NULL;
peSurface = peSurface->peSurface_DdNext)
{
if (!(peSurface->bLost))
{
vDdDisableSurfaceObject(peDirectDrawGlobal,
peSurface,
NULL);
}
}
vDdDisableDirectDrawObject(peDirectDrawLocal);
}
ASSERTGDI(peDirectDrawGlobal->cSurfaceLocks == 0,
"There was a mismatch between global count of locks and actual");
}
/******************************Public*Routine******************************\
* VOID GreDisableDirectDraw
*
* Temporarily disables DirectDraw for the specified device.
*
* NOTE: Caller must be holding User critical section.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
GreDisableDirectDraw(
HDEV hdev,
BOOL bNewMode // FALSE when the mode won't change (used
) // for stuff like switching from full-
// screen DOS mode)
{
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
LONG* pl;
// 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:
pl = (PLONG) &gpGdiSharedMemory->iDisplaySettingsUniqueness;
InterlockedIncrement(pl);
PDEVOBJ po(hdev);
ASSERTGDI(po.bValid(), "Invalid HDEV");
peDirectDrawGlobal = po.peDirectDrawGlobal();
if (peDirectDrawGlobal != NULL)
{
// 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);
}
VACQUIREDEVLOCK(po.pDevLock());
// Increment the disable lock-count event if a DirectDraw global
// object hasn't been created:
po.cDirectDrawDisableLocks(po.cDirectDrawDisableLocks() + 1);
if (peDirectDrawGlobal != NULL)
{
vDdDisableAllDirectDrawObjects(peDirectDrawGlobal);
if (bNewMode)
{
peDirectDrawGlobal->fl |= DD_GLOBAL_FLAG_MODE_CHANGED;
if (peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_DRIVER_ENABLED)
{
vDdDisableDriver(peDirectDrawGlobal);
}
}
}
VRELEASEDEVLOCK(po.pDevLock());
}
/******************************Public*Routine******************************\
* VOID GreEnableDirectDraw
*
* Permits DirectDraw to be reenabled for the specified device.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
GreEnableDirectDraw(
HDEV hdev
)
{
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
LONG* pl;
// 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.
pl = (PLONG) &gpGdiSharedMemory->iDisplaySettingsUniqueness;
InterlockedIncrement(pl);
PDEVOBJ po(hdev);
ASSERTGDI(po.bValid() && po.bDisplayPDEV(), "Invalid HDEV");
// Decrement the disable lock-count even if a DirectDraw global object
// hasn't been created:
VACQUIREDEVLOCK(po.pDevLock());
ASSERTGDI(po.cDirectDrawDisableLocks() != 0,
"Must have called disable previously to be able to enable.");
po.cDirectDrawDisableLocks(po.cDirectDrawDisableLocks() - 1);
peDirectDrawGlobal = po.peDirectDrawGlobal();
if (peDirectDrawGlobal != NULL)
{
// Update the dhpdev for the case where the driver was disabled,
// because there may be a new instance of the driver:
if (po.bModeXEnabled())
{
peDirectDrawGlobal->dhpdev = peDirectDrawGlobal;
}
else
{
peDirectDrawGlobal->dhpdev = po.dhpdev();
}
}
VRELEASEDEVLOCK(po.pDevLock());
}
/******************************Public*Routine******************************\
* VOID pDdLockSurface
*
* Returns a user-mode pointer to the surface.
*
* The devlock must be held to call this function.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID*
pDdLockSurface(
EDD_SURFACE* peSurface,
BOOL bHasRect,
RECTL* pArea,
BOOL bWait, // If accelerator busy, wait until it's not
HRESULT* pResult // ddRVal result of call (may be NULL)
)
{
VOID* pvRet;
DD_LOCKDATA LockData;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
DD_MAPMEMORYDATA MapMemoryData;
DWORD dwTmp;
RECTL rclPointer;
pvRet = NULL;
LockData.ddRVal = DDERR_GENERIC;
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
peDirectDrawLocal = peSurface->peDirectDrawLocal;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
// 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) | (peDirectDrawGlobal->bDisabled))
{
LockData.ddRVal = DDERR_SURFACELOST;
}
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))
{
if (!(peDirectDrawGlobal->CallBacks.dwFlags & DDHAL_CB32_MAPMEMORY))
{
peDirectDrawLocal->fl |= DD_LOCAL_FLAG_MEMORY_MAPPED;
}
else
{
ASSERTGDI(peSurface->cLocks == 0,
"There's a surface lock but the memory isn't mapped?!?");
MapMemoryData.lpDD = peDirectDrawGlobal;
MapMemoryData.bMap = TRUE;
MapMemoryData.hProcess = NtCurrentProcess();
MapMemoryData.fpProcess = NULL;
peDirectDrawGlobal->CallBacks.MapMemory(&MapMemoryData);
LockData.ddRVal = MapMemoryData.ddRVal;
if (MapMemoryData.ddRVal == DD_OK)
{
peDirectDrawLocal->fpProcess = MapMemoryData.fpProcess;
peDirectDrawLocal->fl |= DD_LOCAL_FLAG_MEMORY_MAPPED;
ASSERTGDI(peDirectDrawLocal->fpProcess != 0,
"Expected non-NULL fpProcess value from MapMemory");
}
else
{
WARNING("pDdLockSurface: Driver failed DdMapMemory\n");
}
}
}
// Only proceed if we were successful in mapping the memory:
if (peDirectDrawLocal->fl & DD_LOCAL_FLAG_MEMORY_MAPPED)
{
LockData.dwFlags = DDLOCK_SURFACEMEMORYPTR;
LockData.lpDD = peDirectDrawGlobal;
LockData.lpDDSurface = peSurface;
LockData.bHasRect = bHasRect;
if (bHasRect)
{
LockData.rArea = *pArea;
}
else
{
LockData.rArea.left = 0;
LockData.rArea.top = 0;
LockData.rArea.right = peSurface->wWidth;
LockData.rArea.bottom = peSurface->wHeight;
}
if ((peSurface->fl & DD_SURFACE_FLAG_CLIP) &&
(peSurface->iVisRgnUniqueness != giVisRgnUniqueness))
{
// 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:
LockData.ddRVal = DDERR_VISRGNCHANGED;
}
else
{
dwTmp = DDHAL_DRIVER_NOTHANDLED;
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags & DDHAL_SURFCB32_LOCK)
{
do {
dwTmp = peDirectDrawGlobal->SurfaceCallBacks.Lock(&LockData);
} while ((bWait) &&
(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)
{
peDirectDrawGlobal->cSurfaceLocks++;
peSurface->iVisRgnUniqueness = giVisRgnUniqueness;
}
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;
}
// We have to handle pointer exclusion when drawing to
// the primary surface:
if (peSurface->fl & DD_SURFACE_FLAG_PRIMARY)
{
// Only tear-down the cursor if the specified rectangle
// intersects with the pointer shape:
rclPointer.left = po.ptlPointer().x
+ po.rclPointerOffset().left;
rclPointer.right = po.ptlPointer().x
+ po.rclPointerOffset().right;
rclPointer.top = po.ptlPointer().y
+ po.rclPointerOffset().top;
rclPointer.bottom = po.ptlPointer().y
+ po.rclPointerOffset().bottom;
if (bDdIntersect(&rclPointer, &LockData.rArea))
{
if (po.bPtrNeedsExcluding() &&
!po.bPtrHidden() &&
!po.bPtrDirectDrawOccluded())
{
po.bPtrDirectDrawOccluded(TRUE);
po.pfnMove()(po.pSurface()->pSurfobj(),
-1,
-1,
NULL);
}
}
// Tear down the drag rectangle, if there is one.
// Note that this must come before peSurface->rclLock
// is modified because it must use the old unlocked
// region.
if (po.bHaveDragRect())
{
bDrawDragRectangles(po, (ERECTL*) &LockData.rArea);
}
// Now that we've torn down the drag rect, that region
// is about to be marked as out-of-bounds, so invalid
// the valid flag:
peDirectDrawGlobal->fl
|= DD_GLOBAL_FLAG_UNLOCKED_REGION_INVALID;
}
// Stash away surface lock data:
peSurface->rclLock = LockData.rArea;
if ((peSurface->fl & DD_SURFACE_FLAG_PRIMARY) &&
(peSurface->cLocks == 1))
{
// Add this surface to the head of the locked list:
peSurface->peSurface_LockNext
= peDirectDrawGlobal->peSurface_LockList;
peDirectDrawGlobal->peSurface_LockList = peSurface;
}
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;
}
else
{
pvRet = (VOID*) (peDirectDrawLocal->fpProcess
+ peSurface->fpVidMem);
// 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)));
}
}
ASSERTGDI(pvRet != NULL,
"Expected non-NULL lock pointer value");
ASSERTGDI((ULONG) pvRet < MM_USER_PROBE_ADDRESS,
"Expected user-mode lock pointer value");
}
else
{
if (LockData.ddRVal != DDERR_WASSTILLDRAWING)
{
WARNING("pDdLockSurface: Driver failed DdLock\n");
}
}
}
}
}
VRELEASEDEVLOCK(po.pDevLock());
if (pResult)
{
*pResult = LockData.ddRVal;
}
return(pvRet);
}
/******************************Public*Routine******************************\
* BOOL bDdUnlockSurface
*
* DirectDraw unlock.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
bDdUnlockSurface(
EDD_SURFACE* peSurface
)
{
BOOL b;
BOOL bRedraw;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
b = FALSE;
bRedraw = FALSE;
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
// Make sure there was a previous lock:
if (peSurface->cLocks > 0)
{
ASSERTGDI(!po.bDisabled() || po.bModeXEnabled(),
"Surface is disabled but there are outstanding locks?");
vDdRelinquishSurfaceLock(peDirectDrawGlobal, peSurface);
if (peSurface->cLocks == 0)
{
// If the API-disabled flag is set and we got this far into
// Unlock, it means that there is a GreDisableDirectDraw()
// 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 ((peDirectDrawGlobal->cSurfaceLocks == 0) &&
(peDirectDrawGlobal->bDisabled))
{
KeSetEvent(peDirectDrawGlobal->pAssertModeEvent,
0,
FALSE);
}
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 != giVisRgnUniqueness)
{
// 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
{
WARNING("bDdUnlockSurface: Surface already unlocked\n");
}
VRELEASEDEVLOCK(po.pDevLock());
if (bRedraw)
{
// This call must be done outside of the devlock, otherwise we
// could dead-lock, because user needs to acquire its critical
// section:
DD_ASSERTNODEVLOCK(peDirectDrawGlobal);
UserRedrawDesktop();
}
return(b);
}
/******************************Public*Routine******************************\
* HANDLE NtGdiDdCreateDirectDrawObject
*
* Creates a DirectDraw object.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
HANDLE
APIENTRY
NtGdiDdCreateDirectDrawObject(
HDC hdc
)
{
HANDLE hDirectDrawLocal;
hDirectDrawLocal = 0; // 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 ((W32GetCurrentProcess()->W32PF_Flags & (W32PF_READSCREENACCESSGRANTED | W32PF_IOWINSTA)) ==
(W32PF_READSCREENACCESSGRANTED | W32PF_IOWINSTA))
{
XDCOBJ dco(hdc);
if (dco.bValid())
{
PDEVOBJ po(dco.hdev());
if (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:
VACQUIREDEVLOCK(po.pDevLock());
hDirectDrawLocal = hDdCreateDirectDrawLocal(po);
VRELEASEDEVLOCK(po.pDevLock());
}
dco.vUnlockFast();
}
}
else
{
WARNING("NtGdiDdCreateDirectDrawObject: Don't have screen read permission");
}
return(hDirectDrawLocal);
}
/******************************Public*Routine******************************\
* BOOL NtGdiDdDeleteDirectDrawObject
*
* Deletes a kernel-mode representation of the surface.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
APIENTRY
NtGdiDdDeleteDirectDrawObject(
HANDLE hDirectDrawLocal
)
{
return(bDdDeleteDirectDrawObject(hDirectDrawLocal, FALSE));
}
/******************************Public*Routine******************************\
* HANDLE NtGdiDdQueryDirectDrawObject
*
* Queries a DirectDraw object.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
APIENTRY
NtGdiDdQueryDirectDrawObject(
HANDLE hDirectDrawLocal,
DD_HALINFO* pHalInfo,
DWORD* pCallBackFlags,
DWORD* pNumHeaps,
VIDEOMEMORY* pvmList,
DWORD* pNumFourCC,
DWORD* pFourCC
)
{
BOOL b;
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
ULONG cBytes;
b = FALSE; // Assume failure
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDrawLocal);
if (peDirectDrawLocal != NULL)
{
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
if (peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_DRIVER_ENABLED)
{
__try
{
ProbeAndWriteStructure(pHalInfo,
peDirectDrawGlobal->HalInfo,
DD_HALINFO);
ProbeForWrite(pCallBackFlags, 3 * sizeof(ULONG), sizeof(ULONG));
pCallBackFlags[0] = peDirectDrawGlobal->CallBacks.dwFlags;
pCallBackFlags[1] = peDirectDrawGlobal->SurfaceCallBacks.dwFlags;
pCallBackFlags[2] = peDirectDrawGlobal->PaletteCallBacks.dwFlags;
ProbeAndWriteUlong(pNumHeaps, peDirectDrawGlobal->dwNumHeaps);
ProbeAndWriteUlong(pNumFourCC, peDirectDrawGlobal->dwNumFourCC);
if (pvmList != NULL)
{
cBytes = sizeof(VIDEOMEMORY) * peDirectDrawGlobal->dwNumHeaps;
ProbeForWrite(pvmList, cBytes, sizeof(ULONG));
RtlCopyMemory(pvmList, peDirectDrawGlobal->pvmList, cBytes);
}
if (pFourCC != NULL)
{
cBytes = sizeof(ULONG) * peDirectDrawGlobal->dwNumFourCC;
ProbeForWrite(pFourCC, cBytes, sizeof(ULONG));
RtlCopyMemory(pFourCC, peDirectDrawGlobal->pdwFourCC, cBytes);
}
b = TRUE;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("NtGdiDdQueryDirectDrawObject: Passed bad pointers\n");
}
}
else
{
WARNING("NtGdiDdQueryDirectDrawObject: Driver not yet enabled\n");
}
}
else
{
WARNING("NtGdiDdQueryDirectDrawObject: Bad handle or busy\n");
}
return(b);
}
/******************************Public*Routine******************************\
* EDD_SURFACE* peDdAllocateSurfaceObject
*
* Creates a kernel-mode representation of the surface.
*
* NOTE: Leaves the surface exclusive locked!
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
EDD_SURFACE*
peDdAllocateSurfaceObject(
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal,
DD_SURFACE_GLOBAL* pSurfaceGlobal,
DD_SURFACE_LOCAL* pSurfaceLocal
)
{
EDD_SURFACE* peSurface;
peSurface = (EDD_SURFACE*) HmgAlloc(sizeof(EDD_SURFACE),
DD_SURFACE_TYPE,
HMGR_ALLOC_LOCK);
if (peSurface != NULL)
{
peSurface->lpGbl = peSurface;
peSurface->peDirectDrawLocal = peDirectDrawLocal;
peSurface->peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
peSurface->fpVidMem = pSurfaceGlobal->fpVidMem;
peSurface->lPitch = pSurfaceGlobal->lPitch;
peSurface->wWidth = pSurfaceGlobal->wWidth;
peSurface->wHeight = pSurfaceGlobal->wHeight;
peSurface->ddpfSurface = pSurfaceGlobal->ddpfSurface;
peSurface->ddsCaps = pSurfaceLocal->ddsCaps;
// 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:
peSurface->peSurface_DdNext = peDirectDrawLocal->peSurface_DdList;
peDirectDrawLocal->peSurface_DdList = peSurface;
}
return(peSurface);
}
/******************************Public*Routine******************************\
* BOOL bDdValidateSurfaceObject
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
bDdValidateSurfaceObject(
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal,
EDD_SURFACE* peSurface
)
{
FLATPTR fpSurfaceStart;
FLATPTR fpSurfaceEnd;
FLATPTR fpHeapStart;
FLATPTR fpHeapEnd;
VIDEOMEMORY* pvmList;
ULONG i;
if (!(peSurface->fl & DD_SURFACE_FLAG_DRIVER_CREATED))
{
if (!(peSurface->ddpfSurface.dwFlags & DDPF_RGB) ||
(peSurface->ddsCaps.dwCaps & DDSCAPS_OVERLAY))
{
WARNING("bDdValidateSurfaceObject: Bad surface type\n");
return(FALSE);
}
if (peSurface->ddpfSurface.dwRGBBitCount !=
peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount)
{
WARNING("bDdValidateSurfaceObject: Bad bit count\n");
return(FALSE);
}
// Protect against math overflow:
if ((peSurface->wWidth > DD_MAXIMUM_COORDINATE) ||
(peSurface->wWidth <= 0) ||
(peSurface->wHeight > DD_MAXIMUM_COORDINATE) ||
(peSurface->wHeight <= 0))
{
WARNING("bDdValidateSurfaceObject: Bad dimensions");
return(FALSE);
}
}
// dwRGBBitCount is overloaded with dwYUVBitCount:
if (peSurface->ddpfSurface.dwRGBBitCount < 8)
{
WARNING("bDdValidateSurfaceObject: Bad bit count");
return(FALSE);
}
// Don't let the pitch be less than the width in bytes. Note that
// this filters out negative pitches:
if (peSurface->wWidth >
peSurface->lPitch / (peSurface->ddpfSurface.dwRGBBitCount / 8))
{
WARNING("bDdValidateSurfaceObject: Bad pitch");
return(FALSE);
}
if ((peSurface->fpVidMem & 3) || (peSurface->lPitch & 3))
{
WARNING("bDdValidateSurfaceObject: Bad alignment");
return(FALSE);
}
ASSERTGDI((peSurface->fl & DD_SURFACE_FLAG_PRIMARY) ||
(peSurface->fpVidMem != peDirectDrawGlobal->HalInfo.vmiData.fpPrimary),
"Expected primary surface to be marked as such");
// Ensure that the bitmap is contained entirely within one of the
// driver's heaps:
if (!(peSurface->fl & DD_SURFACE_FLAG_PRIMARY))
{
if (peDirectDrawGlobal->pvmList == NULL)
{
WARNING("bDdValidateSurfaceObject: There is no off-screen heap");
return(FALSE);
}
fpSurfaceStart = peSurface->fpVidMem;
fpSurfaceEnd = fpSurfaceStart
+ (peSurface->wHeight - 1) * peSurface->lPitch
+ (peSurface->wWidth
* (peSurface->ddpfSurface.dwRGBBitCount / 8));
for (i = peDirectDrawGlobal->dwNumHeaps, pvmList = peDirectDrawGlobal->pvmList;
i != 0;
i--, pvmList++)
{
fpHeapStart = pvmList->fpStart;
if (pvmList->dwFlags & VIDMEM_ISRECTANGULAR)
{
fpHeapEnd = fpHeapStart + pvmList->dwHeight
* peDirectDrawGlobal->HalInfo.vmiData.lDisplayPitch;
}
else
{
fpHeapEnd = pvmList->fpEnd;
}
if ((fpSurfaceStart >= fpHeapStart) && (fpSurfaceEnd <= fpHeapEnd))
{
// Success, the surface is entirely contained within the heap.
break;
}
}
if (i == 0)
{
KdPrint(("bDdValidateSurfaceObject: %li x %li surface didn't fit in any heap\n",
peSurface->wWidth, peSurface->wHeight));
KdPrint((" fpSurfaceStart: 0x%lx fpSurfaceEnd: 0x%lx\n",
fpSurfaceStart, fpSurfaceEnd, peSurface->wWidth));
KdPrint((" fpHeapStart: 0x%lx fpHeapEnd: 0x%lx\n",
fpHeapStart, fpHeapEnd));
return(FALSE);
}
}
return(TRUE);
}
/******************************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;
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:
fpStartOffset = peSurface->fpVidMem
- peDirectDrawGlobal->HalInfo.vmiData.fpPrimary;
lDisplayPitch = peDirectDrawGlobal->HalInfo.vmiData.lDisplayPitch;
peSurface->yHint = (fpStartOffset / lDisplayPitch);
peSurface->xHint = (fpStartOffset % lDisplayPitch) /
(peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount / 8);
// Make sure some other flags are correct:
peSurface->ddsCaps.dwCaps &= ~DDSCAPS_PRIMARYSURFACE;
if (peSurface->fl & DD_SURFACE_FLAG_PRIMARY)
{
peSurface->ddsCaps.dwCaps |= DDSCAPS_PRIMARYSURFACE;
}
// 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;
peSurface->bLost = FALSE;
}
/******************************Public*Routine******************************\
* HANDLE NtGdiDdCreateSurfaceObject
*
* 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 NtGdiDdCreateSurface, 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 NtGdiDdCreateSurface. This function call will
* then be extraneous.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
HANDLE
APIENTRY
NtGdiDdCreateSurfaceObject(
HANDLE hDirectDrawLocal,
HANDLE hSurface,
PDD_SURFACE_LOCAL pSurfaceLocal,
PDD_SURFACE_GLOBAL pSurfaceGlobal,
BOOL bPrimarySurface
)
{
HANDLE hRet;
DD_SURFACE_LOCAL SurfaceLocal;
DD_SURFACE_GLOBAL SurfaceGlobal;
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
EDD_LOCK_SURFACE eLockSurface;
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
EDD_SURFACE* peSurface;
BOOL bKeepSurface;
hRet = 0;
__try
{
SurfaceLocal = ProbeAndReadStructure(pSurfaceLocal, DD_SURFACE_LOCAL);
SurfaceGlobal = ProbeAndReadStructure(pSurfaceGlobal, DD_SURFACE_GLOBAL);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return(hRet);
}
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDrawLocal);
if (peDirectDrawLocal != NULL)
{
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
if (!(peDirectDrawGlobal->bDisabled))
{
if ((bPrimarySurface) ||
(SurfaceGlobal.fpVidMem
== peDirectDrawGlobal->HalInfo.vmiData.fpPrimary))
{
bPrimarySurface = TRUE;
SurfaceGlobal.fpVidMem
= peDirectDrawGlobal->HalInfo.vmiData.fpPrimary;
SurfaceGlobal.lPitch
= peDirectDrawGlobal->HalInfo.vmiData.lDisplayPitch;
SurfaceGlobal.wWidth
= peDirectDrawGlobal->HalInfo.vmiData.dwDisplayWidth;
SurfaceGlobal.wHeight
= peDirectDrawGlobal->HalInfo.vmiData.dwDisplayHeight;
SurfaceGlobal.ddpfSurface
= peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay;
}
if (hSurface == 0)
{
peSurface = peDdAllocateSurfaceObject(peDirectDrawLocal,
&SurfaceGlobal,
&SurfaceLocal);
}
else
{
peSurface = (EDD_SURFACE*) HmgLock((HOBJ) hSurface,
DD_SURFACE_TYPE);
if (peSurface == NULL)
{
WARNING("NtGdiDdCreateSurfaceObject: hDDSurface wasn't set to 0\n");
}
}
if (peSurface != NULL)
{
bKeepSurface = FALSE;
if (peSurface->fl & DD_SURFACE_FLAG_CREATE_COMPLETE)
{
bKeepSurface = TRUE;
}
else
{
peSurface->dwFlags = pSurfaceLocal->dwFlags;
if (peSurface->fl & DD_SURFACE_FLAG_DRIVER_CREATED)
{
// The surface was already mostly completed at
// CreateSurface time; the only piece of information
// that was incomplete was the location:
peSurface->fpVidMem = SurfaceGlobal.fpVidMem;
}
else
{
// Overlays can only be created only by the driver:
peSurface->ddsCaps.dwCaps &= ~DDSCAPS_OVERLAY;
}
if (bPrimarySurface)
{
peSurface->fl = DD_SURFACE_FLAG_PRIMARY;
// Handle the case where the primary surface is user-
// memory allocated. bDdValidateSurfaceObject will
// handle the case where this fails:
if (peSurface->fpVidMem == DDHAL_PLEASEALLOC_USERMEM)
{
peSurface->fpVidMem = (FLATPTR) EngAllocUserMem(
peSurface->wHeight * peSurface->lPitch,
'pddG');
if (peSurface->fpVidMem != NULL)
{
peSurface->fl |= DD_SURFACE_FLAG_MEM_ALLOCATED;
}
}
}
if (bDdValidateSurfaceObject(peDirectDrawGlobal, peSurface))
{
vDdCompleteSurfaceObject(peDirectDrawLocal, peSurface);
bKeepSurface = TRUE;
}
else
{
WARNING("NtGdiDdCreateSurfaceObject: Failed validation\n");
}
}
if (bKeepSurface)
{
// 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(), FALSE, NULL);
}
}
}
else
{
WARNING("NtGdiDdCreateSurfaceObject: Can't create because disabled\n");
}
}
else
{
WARNING("NtGdiDdCreateSurfaceObject: Bad handle or busy\n");
}
return(hRet);
}
/******************************Public*Routine******************************\
* BOOL NtGdiDdDeleteSurfaceObject
*
* Deletes a kernel-mode representation of the surface.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
APIENTRY
NtGdiDdDeleteSurfaceObject(
HANDLE hSurface
)
{
return(bDdDeleteSurfaceObject(hSurface, FALSE, NULL));
}
/******************************Public*Routine******************************\
* ULONG NtGdiDdResetVisrgn
*
* Registers a window for clipping.
*
* Remembers the current VisRgn state. Must be called before the VisRgn
* is downloaded and used.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
APIENTRY
NtGdiDdResetVisrgn(
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;
// Note that DD_SURFACE_FLAG_CLIP being set does not imply that
// DD_SURFACE_FLAG_PRIMARY must be set, and vice versa.
if (hwnd == 0)
{
peSurface->fl &= ~DD_SURFACE_FLAG_CLIP;
}
else
{
peSurface->fl |= DD_SURFACE_FLAG_CLIP;
peSurface->iVisRgnUniqueness = giVisRgnUniqueness;
}
bRet = TRUE;
}
return(bRet);
}
/******************************Public*Routine******************************\
* ULONG NtGdiDdReenableDirectDrawObject
*
* Resets the DirectDraw object after a mode change or after full-screen.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
APIENTRY
NtGdiDdReenableDirectDrawObject(
HANDLE hDirectDrawLocal,
BOOL* pbNewMode
)
{
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 = UserGetDesktopDC(DCTYPE_DIRECT,
DCTYPE_MEMORY);
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
DCOBJ dco(hdc);
if ((dco.bValidSurf()) && (!dco.bInFullScreen()))
{
RGNOBJ ro(dco.pdc->prgnVis());
if (ro.iComplexity() != NULLREGION)
{
if (po.cDirectDrawDisableLocks() == 0)
{
ASSERTGDI(!po.bDisabled() || po.bModeXEnabled(),
"Can't be full-screen and re-enable");
bModeChanged
= (peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_MODE_CHANGED) != 0;
// If DirectDraw is already enabled, return TRUE from this call:
b = TRUE;
if (peDirectDrawGlobal->bDisabled)
{
if (!(peDirectDrawGlobal->fl & DD_GLOBAL_FLAG_DRIVER_ENABLED))
{
b = bDdEnableDriver(peDirectDrawGlobal);
}
if (b)
{
peDirectDrawGlobal->fl &= ~DD_GLOBAL_FLAG_MODE_CHANGED;
peDirectDrawGlobal->bDisabled = FALSE;
__try
{
ProbeAndWriteStructure(pbNewMode, bModeChanged, BOOL);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
}
}
}
}
VRELEASEDEVLOCK(po.pDevLock());
if (hdc)
{
bDeleteDCInternal(hdc, FALSE, FALSE);
}
}
else
{
WARNING("NtGdiDdReenableDirectDrawObject: Bad handle or busy\n");
}
return(b);
}
/******************************Public*Routine******************************\
* HDC NtGdiDdGetDC
*
* 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
NtGdiDdGetDC(
HANDLE hSurface
)
{
EDD_LOCK_SURFACE eLockSurface;
EDD_SURFACE* peSurface;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
HDC hdc;
HBITMAP hbm;
DEVBITMAPINFO dbmi;
VOID* pvScan0;
VOID* pvBits;
LONG cjBits;
ULONG iMode;
BOOL b;
// !!! Mark DIBSection so that only DirectDraw can select it into a DC
// !!! Test DIBSections to ensure that an can't do a DdLock(), and pass
// that into CreateDIBSection
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;
// The surface must be marked as RGB (even at 8bpp).
if (peSurface->ddpfSurface.dwFlags & DDPF_RGB)
{
PALMEMOBJ palPerm;
PDEVOBJ po(peDirectDrawGlobal->hdev);
dbmi.cxBitmap = peSurface->wWidth;
dbmi.cyBitmap = peSurface->wHeight;
dbmi.fl = BMF_TOPDOWN;
if (peSurface->lPitch < 0)
{
dbmi.fl = 0;
}
// Grab the devlock to protect against dynamic mode switches
// while we're looking at po.ppalSurface():
DEVLOCKOBJ dlo(po);
if (peSurface->ddpfSurface.dwRGBBitCount == 8)
{
dbmi.iFormat = BMF_8BPP;
// Because at 8bpp the colour table is shared with the display,
// the display must be 8bpp if the surface is 8bpp for the
// call to succeed:
if ((!po.bIsPalManaged()) ||
(peDirectDrawGlobal->HalInfo.vmiData.ddpfDisplay.dwRGBBitCount != 8) ||
(!palPerm.bCreatePalette(PAL_INDEXED,
256,
NULL,
0,
0,
0,
PAL_FIXED)))
{
WARNING("NtGdiDdGetDC: bCreatePalette failed\n");
return(0);
}
// Make this DIBSection share the same colour table as the
// screen, so that we always get identity blts:
palPerm.apalColorSet(po.ppalSurf());
}
else
{
switch (peSurface->ddpfSurface.dwRGBBitCount)
{
case 16:
dbmi.iFormat = BMF_16BPP; break;
case 24:
dbmi.iFormat = BMF_24BPP; break;
case 32:
dbmi.iFormat = BMF_32BPP; break;
default:
RIP("NtGdiDdGetDC: Illegal dwRGBBitCount encountered\n");
}
iMode = PAL_BITFIELDS;
// Check for special cases. Why this isn't done in
// bCreatePalette, I don't know.
if ((peSurface->ddpfSurface.dwRBitMask == 0x0000ff) &&
(peSurface->ddpfSurface.dwGBitMask == 0x00ff00) &&
(peSurface->ddpfSurface.dwBBitMask == 0xff0000))
{
iMode = PAL_RGB;
}
if ((peSurface->ddpfSurface.dwRBitMask == 0xff0000) &&
(peSurface->ddpfSurface.dwGBitMask == 0x00ff00) &&
(peSurface->ddpfSurface.dwBBitMask == 0x0000ff))
{
iMode = PAL_BGR;
}
if (!palPerm.bCreatePalette(iMode,
0,
NULL,
peSurface->ddpfSurface.dwRBitMask,
peSurface->ddpfSurface.dwGBitMask,
peSurface->ddpfSurface.dwBBitMask,
PAL_FIXED))
{
WARNING("NtGdiDdGetDC: bCreatePalette failed\n");
return(0);
}
}
palPerm.flPal(PAL_DIBSECTION);
dbmi.hpal = (HPALETTE) palPerm.hpal();
// 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 = pDdLockSurface(peSurface, FALSE, NULL, TRUE, NULL);
if (pvScan0 != NULL)
{
SURFMEM SurfDimo;
pvBits = pvScan0;
cjBits = (LONG) peSurface->wHeight * peSurface->lPitch;
if (cjBits < 0)
{
cjBits = -cjBits;
pvBits = (BYTE*) pvScan0 - cjBits - peSurface->lPitch;
}
if (SurfDimo.bCreateDIB(&dbmi, pvBits))
{
// Override some fields which we couldn't specify in
// the 'bCreateDIB' call. The following 3 are due to
// the fact that we couldn't pass in a stride:
SurfDimo.ps->lDelta(peSurface->lPitch);
SurfDimo.ps->pvScan0(pvScan0);
SurfDimo.ps->cjBits(cjBits);
// Make sure that the SYNCHRONIZEACCESS flag is set so
// that the devlock is always acquired before drawing to
// the surface -- needed so that we can switch to a
// different mode and 'turn-off' access to the surface
// by changing the clipping:
SurfDimo.ps->flags(SurfDimo.ps->flags()
| HOOK_SYNCHRONIZEACCESS);
SurfDimo.ps->fjBitmap(SurfDimo.ps->fjBitmap() |
BMF_DONTCACHE);
PDEVREF pr(po.hdev());
// Now, create the DC for the actual drawing:
hdc = hdcCreate(pr, DCTYPE_MEMORY, FALSE);
if (hdc)
{
b = FALSE;
// We need to acquire the devlock to add this DC
// to the list hanging off the DirectDraw global
// object:
PDEVOBJ po(peDirectDrawGlobal->hdev);
DD_ASSERTDEVLOCK(peDirectDrawGlobal);
// If the surface is no longer active, that means
// that someone called GreDisableDirectDraw after
// the pDdLockSurface and so the memory mapping into
// the application's address space has been blown
// away. Consequently, we must fail this call:
if (!(peSurface->bLost))
{
peSurface->peSurface_DcNext
= peDirectDrawGlobal->peSurface_DcList;
peDirectDrawGlobal->peSurface_DcList
= peSurface;
peSurface->hdc = hdc;
b = TRUE;
}
if (b)
{
// Since the created DC is unlocked at this point,
// there is a moment of opportunity where the
// application could guess the handle and lock it
// on another thread -- so we have to check for
// bValid() on the DC lock:
DCOBJ dco(hdc);
if (dco.bValid())
{
// Success! Mark it as a DIBSection so that
// we don't do user-mode batching when drawing
// to it. Note that this isn't truly needed
// with the current DirectDraw API, since it
// does not allow direct surface access when
// using a GetDC DC.
dco.pdc->vDIBSection(TRUE);
// We are guaranteed not to truly be in full-
// screen mode, and we have to turn off the
// full-screen bit for DC's constructed around
// ModeX surfaces. (Because when in ModeX mode
// we mark the PDEV as full-screen, the DC is
// automatically marked as full-screen at
// creation):
dco.pdc->bInFullScreen(FALSE);
// Finally, select our surface into the DC:
if (!GreSelectBitmap(hdc,
(HBITMAP) SurfDimo.ps->hsurf()))
{
RIP("NtGdiDdGetDC: GreSelectBitmap failed\n");
}
SurfDimo.vKeepIt();
palPerm.vKeepIt();
return(hdc);
}
}
bDeleteDCInternal(hdc, TRUE, FALSE);
}
else
{
WARNING("NtGdiDdGetDC: GreCreateCompatibleDC failed\n");
}
}
else
{
WARNING("NtGdiDdGetDC: bCreateDIB failed\n");
}
bDdUnlockSurface(peSurface);
}
else
{
WARNING("NtGdiDdGetDC: pDdLockSurface failed\n");
}
}
else
{
WARNING("NtGdiDdGetDC: Invalid surface or RGB type\n");
}
}
else
{
WARNING("NtGdiDdGetDC: Couldn't lock the surface\n");
}
return(0);
}
/******************************Public*Routine******************************\
* BOOL NtGdiDdReleaseDC
*
* Deletes a DC created via DdGetDC.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
APIENTRY
NtGdiDdReleaseDC(
HANDLE hSurface
)
{
BOOL bRet;
EDD_LOCK_SURFACE eLockSurface;
EDD_SURFACE* peSurface;
EDD_SURFACE* peTmp;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
HDC hdc;
HBITMAP hbm;
bRet = FALSE;
peSurface = eLockSurface.peLock(hSurface);
if (peSurface != NULL)
{
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
// We need to acquire the devlock to remove the DC from the DC
// chain:
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
hdc = peSurface->hdc;
hbm = 0;
if (hdc)
{
hbm = GreSelectBitmap(hdc, STOCKOBJ_BITMAP);
if (hbm)
{
peSurface->hdc = 0;
// Remove from the DC surface linked-list:
if (peDirectDrawGlobal->peSurface_DcList == peSurface)
{
peDirectDrawGlobal->peSurface_DcList = peSurface->peSurface_DcNext;
}
else
{
for (peTmp = peDirectDrawGlobal->peSurface_DcList;
peTmp->peSurface_DcNext != peSurface;
peTmp = peTmp->peSurface_DcNext)
;
peTmp->peSurface_DcNext = peSurface->peSurface_DcNext;
}
}
else
{
// If we couldn't select a stock bitmap, then the DC is
// in use. Because it's still got a surface selected with
// a pointer to off-screen memory, we have to be careful
// if the frame buffer is unmapped because the DC could
// still be used and GDI would AV. To avoid this, we leave
// the surface in the DC list -- it will be marked as
// full-screen when the frame buffer is unmapped.
WARNING("NtGdiDdReleaseDC: Couldn't select stock bitmap\n");
}
}
VRELEASEDEVLOCK(po.pDevLock());
if (hbm)
{
// 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 (!bDeleteDCInternal(hdc, TRUE, FALSE))
{
WARNING("NtGdiDdReleaseDC: Couldn't delete DC\n");
}
// Note that bDeleteSurface takes care of dereferencing the
// palette we associated with the surface:
if (!bDeleteSurface((HSURF) hbm))
{
WARNING("NtGdiDdReleaseDC: Couldn't delete surface\n");
}
if (!bDdUnlockSurface(peSurface))
{
WARNING("NtGdiDdReleaseDC: Couldn't unlock surface\n");
}
bRet = TRUE;
}
}
return(bRet);
}
/******************************Public*Routine******************************\
* HANDLE NtGdiDdDuplicateSurface
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
HANDLE
APIENTRY
NtGdiDdDuplicateSurface(
HANDLE hSurface
)
{
return(0);
}
/******************************Public*Routine******************************\
* BOOL NtGdiDdDisableAllSurfaces
*
* Disables all active DirectDraw surfaces so that the new process may
* acquire exclusive use of off-screen memory and page flipping.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
APIENTRY
NtGdiDdDisableAllSurfaces(
HANDLE hDirectDrawLocal
)
{
BOOL b;
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
EDD_DIRECTDRAW_LOCAL* peTmp;
b = FALSE;
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDrawLocal);
if (peDirectDrawLocal != NULL)
{
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
// Disabling all surfaces also calls the driver's DestroySurface.
// Don't do this if running ModeX because doing so also disables
// ModeX:
if (!(peDirectDrawLocal->fl & DD_LOCAL_FLAG_MODEX_ENABLED))
{
vDdDisableAllDirectDrawObjects(peDirectDrawGlobal);
}
VRELEASEDEVLOCK(po.pDevLock());
b = TRUE;
}
else
{
WARNING("NtGdiDdDisableAllSurfaces: Couldn't lock DirectDraw object");
}
return(b);
}
/******************************Public*Routine******************************\
* DWORD NtGdiDdBlt
*
* DirectDraw blt.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD
APIENTRY
NtGdiDdBlt(
HANDLE hSurfaceDest,
HANDLE hSurfaceSrc,
PDD_BLTDATA pBltData
)
{
DWORD dwRet;
DD_BLTDATA BltData;
__try
{
ProbeForRead(pBltData, sizeof(DD_BLTDATA), sizeof(DWORD));
// To save some copying time, we copy only those fields which are
// supported for NT drivers:
BltData.rDest.left = pBltData->rDest.left;
BltData.rDest.top = pBltData->rDest.top;
BltData.rDest.right = pBltData->rDest.right;
BltData.rDest.bottom = pBltData->rDest.bottom;
BltData.rSrc.left = pBltData->rSrc.left;
BltData.rSrc.top = pBltData->rSrc.top;
BltData.rSrc.right = pBltData->rSrc.right;
BltData.rSrc.bottom = pBltData->rSrc.bottom;
BltData.dwFlags = pBltData->dwFlags;
BltData.bltFX.dwFillColor = pBltData->bltFX.dwFillColor;
BltData.bltFX.ddckSrcColorkey = pBltData->bltFX.ddckSrcColorkey;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return(DDHAL_DRIVER_NOTHANDLED);
}
dwRet = DDHAL_DRIVER_NOTHANDLED;
BltData.ddRVal = DDERR_GENERIC;
EDD_SURFACE* peSurfaceDest;
EDD_SURFACE* peSurfaceSrc;
DWORD dwFlags;
EDD_LOCK_SURFACE eLockSurfaceDest;
EDD_LOCK_SURFACE eLockSurfaceSrc;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
peSurfaceDest = eLockSurfaceDest.peLock(hSurfaceDest);
BltData.lpDDDestSurface = peSurfaceDest;
if (peSurfaceDest != NULL)
{
// 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_ASYNC
| DDBLT_WAIT
| DDBLT_COLORFILL
| DDBLT_KEYSRCOVERRIDE
| DDBLT_KEYDESTOVERRIDE
| DDBLT_ROP
| DDBLT_DDFX)) == 0) &&
((dwFlags & (DDBLT_ROP
| DDBLT_COLORFILL)) != 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:
if (BltData.bltFX.dwDDFX & ~DDBLTFX_NOTEARING)
{
WARNING("NtGdiDdBlt: Invalid dwDDFX\n");
return(dwRet);
}
}
if (dwFlags & DDBLT_COLORFILL)
{
// Do simpler stuff 'cause we don't need to lock a source:
BltData.lpDDSrcSurface = NULL;
peSurfaceSrc = NULL;
}
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("NtGdiDdBlt: Invalid source surface or source rectangle\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))
{
peDirectDrawGlobal = peSurfaceDest->peDirectDrawGlobal;
BltData.lpDD = peDirectDrawGlobal;
if (peDirectDrawGlobal->HalInfo.ddCaps.dwCaps & DDCAPS_BLT)
{
// 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.
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
if ((peSurfaceDest->bLost) ||
((peSurfaceSrc != NULL) && (peSurfaceSrc->bLost)))
{
dwRet = DDHAL_DRIVER_HANDLED;
BltData.ddRVal = DDERR_SURFACELOST;
}
else if ((peSurfaceDest->fl & DD_SURFACE_FLAG_CLIP) &&
(peSurfaceDest->iVisRgnUniqueness != giVisRgnUniqueness))
{
// 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
{
DEVEXCLUDEOBJ dxo;
// Exclude the mouse pointer if necessary:
if (peSurfaceDest->fl & DD_SURFACE_FLAG_PRIMARY)
{
dxo.vExclude(peDirectDrawGlobal->hdev,
&BltData.rDest,
NULL);
}
dwRet = peDirectDrawGlobal->SurfaceCallBacks.Blt(&BltData);
}
VRELEASEDEVLOCK(po.pDevLock());
}
}
else
{
WARNING("NtGdiDdBlt: Invalid destination rectangle\n");
}
}
else
{
WARNING("NtGdiDdBlt: Invalid dwFlags\n");
}
}
else
{
WARNING("NtGdiDdBlt: 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
{
pBltData->ddRVal = BltData.ddRVal;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return(dwRet);
}
/******************************Public*Routine******************************\
* DWORD NtGdiDdFlip
*
* DirectDraw flip.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD
APIENTRY
NtGdiDdFlip(
HANDLE hSurfaceCurrent,
HANDLE hSurfaceTarget,
PDD_FLIPDATA pFlipData
)
{
DWORD dwRet;
DD_FLIPDATA FlipData;
__try
{
FlipData = ProbeAndReadStructure(pFlipData, DD_FLIPDATA);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return(DDHAL_DRIVER_NOTHANDLED);
}
dwRet = DDHAL_DRIVER_NOTHANDLED;
FlipData.ddRVal = DDERR_GENERIC;
EDD_SURFACE* peSurfaceCurrent;
EDD_SURFACE* peSurfaceTarget;
EDD_LOCK_SURFACE eLockSurfaceCurrent;
EDD_LOCK_SURFACE eLockSurfaceTarget;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
peSurfaceCurrent = eLockSurfaceCurrent.peLock(hSurfaceCurrent);
peSurfaceTarget = eLockSurfaceTarget.peLock(hSurfaceTarget);
// Make sure surfaces belong to the same DirectDraw object and no
// bad commands are specified:
if ((peSurfaceCurrent != NULL) &&
(peSurfaceTarget != NULL) &&
(peSurfaceCurrent != peSurfaceTarget) &&
(peSurfaceCurrent->peDirectDrawLocal ==
peSurfaceTarget->peDirectDrawLocal) &&
((FlipData.dwFlags & ~DDFLIP_WAIT) == 0))
{
peDirectDrawGlobal = peSurfaceCurrent->peDirectDrawGlobal;
// Make sure that the target is flippable:
if ((peDirectDrawGlobal->SurfaceCallBacks.dwFlags & DDHAL_SURFCB32_FLIP) &&
(peDirectDrawGlobal->HalInfo.ddCaps.ddsCaps.dwCaps & DDSCAPS_FLIP) &&
(peSurfaceCurrent->wHeight == peSurfaceTarget->wHeight) &&
(peSurfaceCurrent->wWidth == peSurfaceTarget->wWidth))
{
FlipData.lpDD = peDirectDrawGlobal;
FlipData.lpSurfCurr = peSurfaceCurrent;
FlipData.lpSurfTarg = peSurfaceTarget;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
if ((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) &&
!(peSurfaceTarget->ddsCaps.dwCaps & DDSCAPS_OVERLAY))
{
peSurfaceCurrent->ddsCaps.dwCaps &= ~DDSCAPS_PRIMARYSURFACE;
peSurfaceTarget->ddsCaps.dwCaps |= DDSCAPS_PRIMARYSURFACE;
peDirectDrawGlobal->peSurfaceCurrent = peSurfaceTarget;
if (peSurfaceCurrent->fl & DD_SURFACE_FLAG_PRIMARY)
{
peDirectDrawGlobal->peSurfacePrimary
= peSurfaceCurrent;
}
}
}
VRELEASEDEVLOCK(po.pDevLock());
}
else
{
WARNING("NtGdiDdFlip: Non-flippable surface\n");
}
}
else
{
WARNING("NtGdiDdFlip: 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
{
pFlipData->ddRVal = FlipData.ddRVal;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return(dwRet);
}
/******************************Public*Routine******************************\
* DWORD NtGdiDdLock
*
* 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
NtGdiDdLock(
HANDLE hSurface,
PDD_LOCKDATA pLockData
)
{
DD_LOCKDATA LockData;
__try
{
LockData = ProbeAndReadStructure(pLockData, 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 = pDdLockSurface(peSurface,
LockData.bHasRect,
&LockData.rArea,
FALSE,
&LockData.ddRVal);
}
else
{
WARNING("NtGdiDdLock: 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
{
pLockData->lpSurfData = LockData.lpSurfData;
pLockData->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 NtGdiDdUnlock
*
* DirectDraw unlock.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD
APIENTRY
NtGdiDdUnlock(
HANDLE hSurface,
PDD_UNLOCKDATA pUnlockData
)
{
DWORD dwRet;
DD_UNLOCKDATA UnlockData;
__try
{
UnlockData = ProbeAndReadStructure(pUnlockData, 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 (bDdUnlockSurface(peSurface))
{
UnlockData.ddRVal = DD_OK;
}
}
else
{
WARNING("NtGdiDdUnlock: 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
{
pUnlockData->ddRVal = UnlockData.ddRVal;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return(DDHAL_DRIVER_HANDLED);
}
/******************************Public*Routine******************************\
* DWORD NtGdiDdGetFlipStatus
*
* DirectDraw API to get the page-flip status.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD
APIENTRY
NtGdiDdGetFlipStatus(
HANDLE hSurface,
PDD_GETFLIPSTATUSDATA pGetFlipStatusData
)
{
DWORD dwRet;
DD_GETFLIPSTATUSDATA GetFlipStatusData;
__try
{
GetFlipStatusData = ProbeAndReadStructure(pGetFlipStatusData,
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) &&
((GetFlipStatusData.dwFlags & ~(DDGFS_CANFLIP
| DDGFS_ISFLIPDONE)) == 0))
{
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags &
DDHAL_SURFCB32_GETFLIPSTATUS)
{
GetFlipStatusData.lpDD = peDirectDrawGlobal;
GetFlipStatusData.lpDDSurface = peSurface;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
if (peSurface->bLost)
{
dwRet = DDHAL_DRIVER_HANDLED;
GetFlipStatusData.ddRVal = DDERR_SURFACELOST;
}
else
{
dwRet = peDirectDrawGlobal->
SurfaceCallBacks.GetFlipStatus(&GetFlipStatusData);
}
VRELEASEDEVLOCK(po.pDevLock());
}
}
else
{
WARNING("NtGdiDdGetFlipStatus: 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
{
pGetFlipStatusData->ddRVal = GetFlipStatusData.ddRVal;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return(dwRet);
}
/******************************Public*Routine******************************\
* DWORD NtGdiDdGetBltStatus
*
* DirectDraw API to get the accelerator's accelerator status.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD
APIENTRY
NtGdiDdGetBltStatus(
HANDLE hSurface,
PDD_GETBLTSTATUSDATA pGetBltStatusData
)
{
DWORD dwRet;
DD_GETBLTSTATUSDATA GetBltStatusData;
__try
{
GetBltStatusData = ProbeAndReadStructure(pGetBltStatusData,
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) &&
((GetBltStatusData.dwFlags & ~(DDGBS_CANBLT
| DDGBS_ISBLTDONE)) == 0))
{
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags &
DDHAL_SURFCB32_GETBLTSTATUS)
{
GetBltStatusData.lpDD = peDirectDrawGlobal;
GetBltStatusData.lpDDSurface = peSurface;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
if (peSurface->bLost)
{
dwRet = DDHAL_DRIVER_HANDLED;
GetBltStatusData.ddRVal = DDERR_SURFACELOST;
}
else
{
dwRet = peDirectDrawGlobal->
SurfaceCallBacks.GetBltStatus(&GetBltStatusData);
}
VRELEASEDEVLOCK(po.pDevLock());
}
}
else
{
WARNING("NtGdiDdGetBltStatus: 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
{
pGetBltStatusData->ddRVal = GetBltStatusData.ddRVal;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return(dwRet);
}
/******************************Public*Routine******************************\
* DWORD NtGdiDdWaitForVerticalBlank
*
* DirectDraw API to wait for vertical blank.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD
APIENTRY
NtGdiDdWaitForVerticalBlank(
HANDLE hDirectDraw,
PDD_WAITFORVERTICALBLANKDATA pWaitForVerticalBlankData
)
{
DWORD dwRet;
DD_WAITFORVERTICALBLANKDATA WaitForVerticalBlankData;
__try
{
WaitForVerticalBlankData =
ProbeAndReadStructure(pWaitForVerticalBlankData,
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;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
if (peDirectDrawGlobal->bDisabled)
{
dwRet = DDHAL_DRIVER_HANDLED;
WaitForVerticalBlankData.ddRVal = DDERR_SURFACELOST;
}
else
{
dwRet = peDirectDrawGlobal->
CallBacks.WaitForVerticalBlank(&WaitForVerticalBlankData);
}
VRELEASEDEVLOCK(po.pDevLock());
}
}
else
{
WARNING("NtGdiDdWaitForVerticalBlank: 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
{
pWaitForVerticalBlankData->ddRVal = WaitForVerticalBlankData.ddRVal;
pWaitForVerticalBlankData->bIsInVB = WaitForVerticalBlankData.bIsInVB;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return(dwRet);
}
/******************************Public*Routine******************************\
* DWORD NtGdiDdCanCreateSurface
*
* 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
NtGdiDdCanCreateSurface(
HANDLE hDirectDraw,
PDD_CANCREATESURFACEDATA pCanCreateSurfaceData
)
{
DWORD dwRet;
DD_CANCREATESURFACEDATA CanCreateSurfaceData;
DDSURFACEDESC* pSurfaceDescription;
DDSURFACEDESC SurfaceDescription;
__try
{
CanCreateSurfaceData = ProbeAndReadStructure(pCanCreateSurfaceData,
DD_CANCREATESURFACEDATA);
pSurfaceDescription = CanCreateSurfaceData.lpDDSurfaceDesc;
SurfaceDescription = ProbeAndReadStructure(pSurfaceDescription,
DDSURFACEDESC);
CanCreateSurfaceData.lpDDSurfaceDesc = &SurfaceDescription;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return(DDHAL_DRIVER_NOTHANDLED);
}
dwRet = DDHAL_DRIVER_NOTHANDLED;
CanCreateSurfaceData.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_CANCREATESURFACE)
{
CanCreateSurfaceData.lpDD = peDirectDrawGlobal;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
if (!peDirectDrawGlobal->bDisabled)
{
dwRet = peDirectDrawGlobal->
CallBacks.CanCreateSurface(&CanCreateSurfaceData);
}
VRELEASEDEVLOCK(po.pDevLock());
}
else
{
WARNING("NtGdiDdCanCreateSurface: Driver doesn't hook call\n");
}
}
else
{
WARNING("NtGdiDdCanCreateSurface: 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
{
pCanCreateSurfaceData->ddRVal = CanCreateSurfaceData.ddRVal;
*CanCreateSurfaceData.lpDDSurfaceDesc = SurfaceDescription;
// Driver can update ddpfPixelFormat.dwYUVBitCount
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return(dwRet);
}
/******************************Public*Routine******************************\
* DWORD NtGdiDdCreateSurface
*
* Calls the driver to create a DirectDraw surface. If the driver can't
* create it, we expect DirectDraw to call NtGdiDdCreateSurfaceObject with
* the location in off-screen memory where DirectDraw itself, not the driver,
* wants to put it.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD
APIENTRY
NtGdiDdCreateSurface(
HANDLE hDirectDraw,
DDSURFACEDESC* pSurfaceDescription,
DD_SURFACE_GLOBAL* pSurfaceGlobalData,
DD_SURFACE_LOCAL* pSurfaceLocalData,
DD_CREATESURFACEDATA* pCreateSurfaceData,
HANDLE* phSurface
)
{
DWORD dwRet;
DD_CREATESURFACEDATA CreateSurfaceData;
DDSURFACEDESC SurfaceDescription;
DD_SURFACE_GLOBAL SurfaceGlobal;
DD_SURFACE_LOCAL SurfaceLocal;
__try
{
CreateSurfaceData = ProbeAndReadStructure(pCreateSurfaceData,
DD_CREATESURFACEDATA);
SurfaceDescription = ProbeAndReadStructure(pSurfaceDescription,
DDSURFACEDESC);
SurfaceGlobal = ProbeAndReadStructure(pSurfaceGlobalData,
DD_SURFACE_GLOBAL);
SurfaceLocal = ProbeAndReadStructure(pSurfaceLocalData,
DD_SURFACE_LOCAL);
ProbeAndWriteUlong((ULONG*) phSurface, 0);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return(DDHAL_DRIVER_NOTHANDLED);
}
dwRet = DDHAL_DRIVER_NOTHANDLED;
CreateSurfaceData.ddRVal = DDERR_GENERIC;
EDD_SURFACE* peSurface;
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
DD_SURFACE_LOCAL* pSurfaceLocal;
HANDLE hRet;
BOOL bKeepSurface;
hRet = 0;
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDraw);
if (peDirectDrawLocal != NULL)
{
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
// Do some basic parameter checking to avoid possible overflows:
if ((peDirectDrawGlobal->CallBacks.dwFlags & DDHAL_CB32_CREATESURFACE) &&
(SurfaceGlobal.wWidth <= DD_MAXIMUM_COORDINATE) &&
(SurfaceGlobal.wWidth > 0) &&
(SurfaceGlobal.wHeight <= DD_MAXIMUM_COORDINATE) &&
(SurfaceGlobal.wHeight > 0))
{
peSurface = peDdAllocateSurfaceObject(peDirectDrawLocal,
&SurfaceGlobal,
&SurfaceLocal);
if (peSurface != NULL)
{
bKeepSurface = FALSE;
pSurfaceLocal = peSurface;
peSurface->fpVidMem = 0;
CreateSurfaceData.lpDD = peDirectDrawGlobal;
CreateSurfaceData.lpDDSurfaceDesc = &SurfaceDescription;
CreateSurfaceData.lplpSList = &pSurfaceLocal;
CreateSurfaceData.dwSCnt = 1;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
if (!peDirectDrawGlobal->bDisabled)
{
dwRet = peDirectDrawGlobal->
CallBacks.CreateSurface(&CreateSurfaceData);
}
VRELEASEDEVLOCK(po.pDevLock());
if (((dwRet == DDHAL_DRIVER_HANDLED) &&
(CreateSurfaceData.ddRVal == DD_OK)) ||
((dwRet == DDHAL_DRIVER_NOTHANDLED) &&
((peSurface->fpVidMem == DDHAL_PLEASEALLOC_BLOCKSIZE) ||
(peSurface->fpVidMem == DDHAL_PLEASEALLOC_USERMEM))))
{
bKeepSurface = TRUE;
peSurface->fl |= DD_SURFACE_FLAG_DRIVER_CREATED;
// 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 ((dwRet == DDHAL_DRIVER_NOTHANDLED) &&
(peSurface->fpVidMem == DDHAL_PLEASEALLOC_USERMEM))
{
dwRet = DDHAL_DRIVER_HANDLED;
CreateSurfaceData.ddRVal = DD_OK;
peSurface->fpVidMem
= (FLATPTR) EngAllocUserMem(peSurface->dwUserMemSize,
'pddG');
if (peSurface->fpVidMem != 0)
{
peSurface->fl |= DD_SURFACE_FLAG_MEM_ALLOCATED;
}
else
{
bKeepSurface = FALSE;
CreateSurfaceData.ddRVal = DDERR_OUTOFMEMORY;
}
}
// If 'fpVidMem' is DDHAL_PLEASEALLOC_BLOCKSIZE, that means
// the driver wants DirectDraw to allocate space in
// off-screen memory. So DirectDraw will be calling us
// again, this time via NtGdiDdCreateSurfaceObject to tell
// us the off-screen location.
if ((dwRet == DDHAL_DRIVER_NOTHANDLED) &&
(peSurface->fpVidMem == DDHAL_PLEASEALLOC_BLOCKSIZE))
{
// Mark the surface as lost so that it can't be
// used until it's completed:
peSurface->bLost = TRUE;
}
else
{
// The object is already complete. We can ignore the
// following NtGdiDdCreateSurfaceObject call that will
// occur on this object.
vDdCompleteSurfaceObject(peDirectDrawLocal, peSurface);
}
}
if (bKeepSurface)
{
// We were successful, so unlock the surface:
hRet = peSurface->hGet();
DEC_EXCLUSIVE_REF_CNT(peSurface);
}
else
{
// Delete the surface. Note that it may or may not
// yet have been completed:
bDdDeleteSurfaceObject(peSurface->hGet(), FALSE, NULL);
if (dwRet != DDHAL_DRIVER_NOTHANDLED)
{
WARNING("NtGdiDdCreateSurface: Driver failed call\n");
}
}
}
else
{
WARNING("NtGdiDdCreateSurface: Couldn't allocate surface\n");
}
}
else
{
WARNING("NtGdiDdCreateSurface: Bad surface dimensions\n");
}
}
else
{
WARNING("NtGdiDdCreateSurface: 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
{
if (bKeepSurface)
{
pCreateSurfaceData->ddRVal = CreateSurfaceData.ddRVal;
*pSurfaceDescription = SurfaceDescription;
*pSurfaceGlobalData = *peSurface;
*phSurface = hRet;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return(dwRet);
}
/******************************Public*Routine******************************\
* DWORD NtGdiDdDestroySurface
*
* Calls the driver to delete a surface it created via CreateSurface.
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD
APIENTRY
NtGdiDdDestroySurface(
HANDLE hSurface
)
{
DWORD dwRet;
bDdDeleteSurfaceObject(hSurface, FALSE, &dwRet);
return(dwRet);
}
/******************************Public*Routine******************************\
* DWORD NtGdiDdSetColorKey
*
* 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
NtGdiDdSetColorKey(
HANDLE hSurface,
PDD_SETCOLORKEYDATA pSetColorKeyData
)
{
DWORD dwRet;
DD_SETCOLORKEYDATA SetColorKeyData;
__try
{
SetColorKeyData = ProbeAndReadStructure(pSetColorKeyData,
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) &&
((SetColorKeyData.dwFlags & ~(DDCKEY_COLORSPACE
| DDCKEY_DESTBLT
| DDCKEY_DESTOVERLAY
| DDCKEY_SRCBLT
| DDCKEY_SRCOVERLAY)) == 0))
{
peDirectDrawGlobal = peSurface->peDirectDrawGlobal;
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags &
DDHAL_SURFCB32_SETCOLORKEY)
{
SetColorKeyData.lpDD = peDirectDrawGlobal;
SetColorKeyData.lpDDSurface = peSurface;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
if (peSurface->bLost)
{
dwRet = DDHAL_DRIVER_HANDLED;
SetColorKeyData.ddRVal = DDERR_SURFACELOST;
}
else
{
dwRet = peDirectDrawGlobal->
SurfaceCallBacks.SetColorKey(&SetColorKeyData);
}
VRELEASEDEVLOCK(po.pDevLock());
}
}
else
{
WARNING("NtGdiDdSetColorKey: 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
{
pSetColorKeyData->ddRVal = SetColorKeyData.ddRVal;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return(dwRet);
}
/******************************Public*Routine******************************\
* DWORD NtGdiDdUpdateOverlay
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD
APIENTRY
NtGdiDdUpdateOverlay(
HANDLE hSurfaceDestination,
HANDLE hSurfaceSource,
PDD_UPDATEOVERLAYDATA pUpdateOverlayData
)
{
DWORD dwRet;
DD_UPDATEOVERLAYDATA UpdateOverlayData;
__try
{
UpdateOverlayData = ProbeAndReadStructure(pUpdateOverlayData,
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_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_OVERLAY) &&
(UpdateOverlayData.dwFlags & ~(DDOVER_HIDE
| DDOVER_KEYDEST
| DDOVER_KEYDESTOVERRIDE
| DDOVER_KEYSRC
| DDOVER_KEYSRCOVERRIDE
| DDOVER_SHOW
| DDOVER_DDFX)) == 0)
{
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->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("NtGdiDdUpdateOverlay: 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("NtGdiDdUpdateOverlay: Expected user-mode to set OVERRIDE\n");
}
}
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags
& DDHAL_SURFCB32_UPDATEOVERLAY)
{
UpdateOverlayData.lpDD = peDirectDrawGlobal;
UpdateOverlayData.lpDDDestSurface = peSurfaceDestination;
UpdateOverlayData.lpDDSrcSurface = peSurfaceSource;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
if ((peSurfaceSource->bLost) ||
((peSurfaceDestination != NULL) && (peSurfaceDestination->bLost)))
{
dwRet = DDHAL_DRIVER_HANDLED;
UpdateOverlayData.ddRVal = DDERR_SURFACELOST;
}
else
{
dwRet = peDirectDrawGlobal->SurfaceCallBacks.UpdateOverlay(
&UpdateOverlayData);
}
VRELEASEDEVLOCK(po.pDevLock());
}
}
else
{
WARNING("NtGdiDdUpdateOverlay: 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
{
pUpdateOverlayData->ddRVal = UpdateOverlayData.ddRVal;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return(dwRet);
}
/******************************Public*Routine******************************\
* DWORD NtGdiDdSetOverlayPosition
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD
APIENTRY
NtGdiDdSetOverlayPosition(
HANDLE hSurfaceSource,
HANDLE hSurfaceDestination,
PDD_SETOVERLAYPOSITIONDATA pSetOverlayPositionData
)
{
DWORD dwRet;
DD_SETOVERLAYPOSITIONDATA SetOverlayPositionData;
__try
{
SetOverlayPositionData = ProbeAndReadStructure(pSetOverlayPositionData,
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))
{
peDirectDrawGlobal = peSurfaceSource->peDirectDrawGlobal;
if (peDirectDrawGlobal->SurfaceCallBacks.dwFlags &
DDHAL_SURFCB32_SETOVERLAYPOSITION)
{
SetOverlayPositionData.lpDD = peDirectDrawGlobal;
SetOverlayPositionData.lpDDSrcSurface = peSurfaceSource;
SetOverlayPositionData.lpDDDestSurface = peSurfaceDestination;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
if ((peSurfaceSource->bLost) || (peSurfaceDestination->bLost))
{
dwRet = DDHAL_DRIVER_HANDLED;
SetOverlayPositionData.ddRVal = DDERR_SURFACELOST;
}
else
{
dwRet = peDirectDrawGlobal->
SurfaceCallBacks.SetOverlayPosition(&SetOverlayPositionData);
}
VRELEASEDEVLOCK(po.pDevLock());
}
}
else
{
WARNING("NtGdiDdSetOverlayPosition: 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
{
pSetOverlayPositionData->ddRVal = SetOverlayPositionData.ddRVal;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return(dwRet);
}
/******************************Public*Routine******************************\
* DWORD NtGdiDdGetScanLine
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD
APIENTRY
NtGdiDdGetScanLine(
HANDLE hDirectDraw,
PDD_GETSCANLINEDATA pGetScanLineData
)
{
DWORD dwRet;
DD_GETSCANLINEDATA GetScanLineData;
__try
{
GetScanLineData = ProbeAndReadStructure(pGetScanLineData,
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;
PDEVOBJ po(peDirectDrawGlobal->hdev);
VACQUIREDEVLOCK(po.pDevLock());
if (peDirectDrawGlobal->bDisabled)
{
dwRet = DDHAL_DRIVER_HANDLED;
GetScanLineData.ddRVal = DDERR_SURFACELOST;
}
else
{
dwRet = peDirectDrawGlobal->
CallBacks.GetScanLine(&GetScanLineData);
}
VRELEASEDEVLOCK(po.pDevLock());
}
}
else
{
WARNING("NtGdiDdGetScanLine: 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
{
pGetScanLineData->ddRVal = GetScanLineData.ddRVal;
pGetScanLineData->dwScanLine = GetScanLineData.dwScanLine;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return(dwRet);
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
/******************************Module*Header*******************************\
* This section contains the logic for a ModeX DirectDraw driver.
*
* This was written with the intent that once NT has the capability of
* dynamically switching display drivers, that this be moved into a VGA256
* or MODEX driver for a cleaner implementation.
*
* Created: 3-Dec-1995
* Author: J. Andrew Goossen [andrewgo]
\**************************************************************************/
#define VGA_BASE 0x300 // Base address of the VGA (3xx)
#define SEQ_ADDR 0xC4 // SEQUencer Address Register
#define SEQ_DATA 0xC5 // SEQUencer Data Register
#define SEQ_MAP_MASK 0x02 // Write Plane Enable Mask
#define CRTC_ADDR 0x0D4 // CRTC Address Register for color mode
#define CRTC_DATA 0x0D5 // CRTC Data Register for color mode
#define START_ADDRESS_HIGH 0x0C // Index for Frame Buffer Start
#define IN_STAT_1 0x0DA // Input Status Register 1
#define IN_VBLANK(pjBase) (READ_PORT_UCHAR(pjBase + VGA_BASE + IN_STAT_1) & 0x8)
// We only program the high byte of the offset, so the page size must be
// a multiple of 256.
#define SCREEN_PAGE_SIZE ((80 * 240 + 255) & ~255)
/******************************Public*Routine******************************\
* DWORD ModeXWaitForVerticalBlank
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD ModeXWaitForVerticalBlank(
PDD_WAITFORVERTICALBLANKDATA lpWaitForVerticalBlank)
{
EDD_DIRECTDRAW_GLOBAL* ppdev;
BYTE* pjBase;
ppdev = (EDD_DIRECTDRAW_GLOBAL*) lpWaitForVerticalBlank->lpDD->dhpdev;
pjBase = ppdev->pjModeXBase;
lpWaitForVerticalBlank->ddRVal = DD_OK;
switch (lpWaitForVerticalBlank->dwFlags)
{
case DDWAITVB_I_TESTVB:
lpWaitForVerticalBlank->bIsInVB = (IN_VBLANK(pjBase) != 0);
break;
case DDWAITVB_BLOCKBEGIN:
while (IN_VBLANK(pjBase))
;
while (!IN_VBLANK(pjBase))
;
break;
case DDWAITVB_BLOCKEND:
while (!IN_VBLANK(pjBase))
;
while (IN_VBLANK(pjBase))
;
break;
}
return(DDHAL_DRIVER_HANDLED);
}
/******************************Public*Routine******************************\
* DWORD ModeXCreateSurface
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD ModeXCreateSurface(
PDD_CREATESURFACEDATA lpCreateSurface)
{
EDD_DIRECTDRAW_GLOBAL* ppdev;
PDD_SURFACE_GLOBAL pSurfaceGlobal;
PDD_SURFACEDESC pSurfaceDesc;
VOID* pv;
ppdev = (EDD_DIRECTDRAW_GLOBAL*) lpCreateSurface->lpDD->dhpdev;
pSurfaceGlobal = lpCreateSurface->lplpSList[0]->lpGbl;
pSurfaceDesc = lpCreateSurface->lpDDSurfaceDesc;
ASSERTGDI(lpCreateSurface->dwSCnt == 1, "Must modify ModeXCreateSurface");
if ((pSurfaceGlobal->wWidth == (ULONG) ppdev->sizlModeX.cx) &&
(pSurfaceGlobal->wHeight == (ULONG) ppdev->sizlModeX.cy))
{
if ((pSurfaceGlobal->ddpfSurface.dwSize != sizeof(DDPIXELFORMAT)) ||
(pSurfaceGlobal->ddpfSurface.dwRGBBitCount == 8))
{
// Returning 'DDHAL_DRIVER_NOTHANDLED' with 'fpVidMem' set to
// 'DDHAL_PLEASEALLOC_USERMEM' will cause DirectDraw to allocate
// user-mode memory on our behalf:
pSurfaceGlobal->fpVidMem = DDHAL_PLEASEALLOC_USERMEM;
pSurfaceGlobal->dwUserMemSize = ppdev->sizlModeX.cx *
ppdev->sizlModeX.cy; // Request size
pSurfaceGlobal->lPitch = ppdev->sizlModeX.cx;
pSurfaceDesc->lPitch = ppdev->sizlModeX.cx;
pSurfaceDesc->dwFlags |= DDSD_PITCH;
}
else
{
WARNING("ModeXCreateSurface: ddpfSurface data doesn't match\n");
}
}
else
{
WARNING("ModeXCreateSurface: Requested dimensions don't match screen\n");
}
return(DDHAL_DRIVER_NOTHANDLED);
}
/******************************Public*Routine******************************\
* DWORD ModeXLock
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD ModeXLock(
PDD_LOCKDATA lpLock)
{
EDD_DIRECTDRAW_GLOBAL* ppdev;
PDD_SURFACE_LOCAL pSurfaceLocal;
PDD_SURFACE_GLOBAL pSurfaceGlobal;
ppdev = (EDD_DIRECTDRAW_GLOBAL*) lpLock->lpDD->dhpdev;
pSurfaceLocal = lpLock->lpDDSurface;
pSurfaceGlobal = pSurfaceLocal->lpGbl;
if (pSurfaceLocal->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
{
// Can't lock the primary surface, because there isn't one.
lpLock->ddRVal = DDERR_CANTLOCKSURFACE;
}
else
{
lpLock->ddRVal = DD_OK;
lpLock->lpSurfData = (VOID*) pSurfaceGlobal->fpVidMem;
// When a driver returns DDHAL_DRIVER_HANDLED, it has to do the
// goofy rectangle offset thing:
if (lpLock->bHasRect)
{
lpLock->lpSurfData = (VOID*) ((BYTE*) lpLock->lpSurfData
+ lpLock->rArea.top * pSurfaceGlobal->lPitch
+ lpLock->rArea.left);
}
}
return(DDHAL_DRIVER_HANDLED);
}
/******************************Public*Routine******************************\
* DWORD ModeXFlip
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
DWORD ModeXFlip(
PDD_FLIPDATA lpFlip)
{
EDD_DIRECTDRAW_GLOBAL* ppdev;
BYTE* pjBase;
ULONG cDwordsPerPlane;
BYTE* pjSourceStart;
BYTE* pjDestinationStart;
BYTE* pjSource;
BYTE* pjDestination;
LONG iPage;
LONG i;
ULONG ul;
ppdev = (EDD_DIRECTDRAW_GLOBAL*) lpFlip->lpDD->dhpdev;
pjBase = ppdev->pjModeXBase;
// Copy from the DIB surface to the current VGA back-buffer. We have
// to convert to planar format on the way:
WRITE_PORT_UCHAR(pjBase + VGA_BASE + SEQ_ADDR, SEQ_MAP_MASK);
cDwordsPerPlane = (ppdev->sizlModeX.cx * ppdev->sizlModeX.cy) >> 4;
pjDestinationStart = ppdev->pjModeXScreen + ppdev->cjModeXScreenOffset;
pjSourceStart = (BYTE*) lpFlip->lpSurfTarg->lpGbl->fpVidMem;
// It doesn't really make sense when asked to flip back to the primary
// surface, so just return success:
if (pjSourceStart != NULL)
{
for (iPage = 0; iPage < 4; iPage++, pjSourceStart++)
{
WRITE_PORT_UCHAR(pjBase + VGA_BASE + SEQ_DATA, 1 << iPage);
#if defined(_X86_)
_asm {
mov esi,pjSourceStart
mov edi,pjDestinationStart
mov ecx,cDwordsPerPlane
PixelLoop:
mov al,[esi+8]
mov ah,[esi+12]
shl eax,16
mov al,[esi]
mov ah,[esi+4]
mov [edi],eax
add edi,4
add esi,16
dec ecx
jnz PixelLoop
}
#else
pjSource = pjSourceStart;
pjDestination = pjDestinationStart;
for (i = cDwordsPerPlane; i != 0; i--)
{
ul = (*(pjSource))
| (*(pjSource + 4) << 8)
| (*(pjSource + 8) << 16)
| (*(pjSource + 12) << 24);
WRITE_REGISTER_ULONG((ULONG*) pjDestination, ul);
pjDestination += 4;
pjSource += 16;
}
#endif
}
// Now flip to the page we just updated:
WRITE_PORT_USHORT((USHORT*) (pjBase + VGA_BASE + CRTC_ADDR),
(USHORT) ((ppdev->cjModeXScreenOffset) & 0xff00) | START_ADDRESS_HIGH);
// Make the following page the current back-buffer. We always flip
// between three pages, so watch for our limit:
ppdev->cjModeXScreenOffset += SCREEN_PAGE_SIZE;
if (++ppdev->iModeXScreen == 3)
{
ppdev->iModeXScreen = 0;
ppdev->cjModeXScreenOffset = 0;
}
}
lpFlip->ddRVal = DD_OK;
return(DDHAL_DRIVER_HANDLED);
}
/******************************Public*Routine******************************\
* BOOL ModeXSetPalette
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
#define MAX_CLUT_SIZE sizeof(VIDEO_CLUT) + (sizeof(ULONG) * 256)
BOOL ModeXSetPalette(
EDD_DIRECTDRAW_GLOBAL* ppdev,
PALOBJ* ppalo,
FLONG fl,
ULONG iStart,
ULONG cColors)
{
BYTE ajClutSpace[MAX_CLUT_SIZE];
PVIDEO_CLUT pScreenClut;
PVIDEO_CLUTDATA pScreenClutData;
// Fill in pScreenClut header info:
pScreenClut = (PVIDEO_CLUT) ajClutSpace;
pScreenClut->NumEntries = (USHORT) cColors;
pScreenClut->FirstEntry = (USHORT) iStart;
pScreenClutData = (PVIDEO_CLUTDATA) (&(pScreenClut->LookupTable[0]));
if (cColors != PALOBJ_cGetColors(ppalo, iStart, cColors,
(ULONG*) pScreenClutData))
{
return(FALSE);
}
// Set the high reserved byte in each palette entry to 0.
// Do the appropriate palette shifting to fit in the DAC.
while (cColors--)
{
pScreenClutData[cColors].Red >>= 2;
pScreenClutData[cColors].Green >>= 2;
pScreenClutData[cColors].Blue >>= 2;
pScreenClutData[cColors].Unused = 0;
}
// Set palette registers
if (EngDeviceIoControl(ppdev->hModeX,
IOCTL_VIDEO_SET_COLOR_REGISTERS,
pScreenClut,
MAX_CLUT_SIZE,
NULL,
0,
&cColors))
{
return(FALSE);
}
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL ModeXGetDirectDrawInfo
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL ModeXGetDirectDrawInfo(
DHPDEV dhpdev,
DD_HALINFO* pHalInfo,
DWORD* pdwNumHeaps,
VIDEOMEMORY* pvmList, // Will be NULL on first call
DWORD* pdwNumFourCC,
DWORD* pdwFourCC) // Will be NULL on first call
{
EDD_DIRECTDRAW_GLOBAL* ppdev;
ppdev = (EDD_DIRECTDRAW_GLOBAL*) dhpdev;
pHalInfo->dwSize = sizeof(*pHalInfo);
// Current primary surface attributes. Since HalInfo is zero-initialized
// by GDI, we only have to fill in the fields which should be non-zero:
pHalInfo->vmiData.dwDisplayWidth = ppdev->sizlModeX.cx;
pHalInfo->vmiData.dwDisplayHeight = ppdev->sizlModeX.cy;
pHalInfo->vmiData.lDisplayPitch = ppdev->sizlModeX.cx;
pHalInfo->vmiData.fpPrimary = DDHAL_PLEASEALLOC_USERMEM;
pHalInfo->vmiData.ddpfDisplay.dwSize = sizeof(DDPIXELFORMAT);
pHalInfo->vmiData.ddpfDisplay.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8;
pHalInfo->vmiData.ddpfDisplay.dwRGBBitCount = 8;
// These masks will be zero at 8bpp:
pHalInfo->vmiData.ddpfDisplay.dwRBitMask = 0;
pHalInfo->vmiData.ddpfDisplay.dwGBitMask = 0;
pHalInfo->vmiData.ddpfDisplay.dwBBitMask = 0;
pHalInfo->vmiData.ddpfDisplay.dwRGBAlphaBitMask = 0;
*pdwNumHeaps = 0;
// Capabilities supported:
pHalInfo->ddCaps.dwFXCaps = 0;
pHalInfo->ddCaps.dwCaps = 0;
pHalInfo->ddCaps.dwCKeyCaps = 0;
pHalInfo->ddCaps.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN
| DDSCAPS_PRIMARYSURFACE
| DDSCAPS_FLIP
| DDSCAPS_MODEX;
// Required alignments of the scan lines for each kind of memory:
pHalInfo->vmiData.dwOffscreenAlign = 8;
// FourCCs supported:
*pdwNumFourCC = 0;
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL ModeXEnableDirectDraw
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL ModeXEnableDirectDraw(
DHPDEV dhpdev,
DD_CALLBACKS* pCallBacks,
DD_SURFACECALLBACKS* pSurfaceCallBacks,
DD_PALETTECALLBACKS* pPaletteCallBacks)
{
pCallBacks->WaitForVerticalBlank = ModeXWaitForVerticalBlank;
pCallBacks->CreateSurface = ModeXCreateSurface;
pCallBacks->dwFlags = DDHAL_CB32_WAITFORVERTICALBLANK
| DDHAL_CB32_CREATESURFACE;
pSurfaceCallBacks->Flip = ModeXFlip;
pSurfaceCallBacks->Lock = ModeXLock;
pSurfaceCallBacks->dwFlags = DDHAL_SURFCB32_FLIP
| DDHAL_SURFCB32_LOCK;
return(TRUE);
}
/******************************Public*Routine******************************\
* VOID ModeXDisableDirectDraw
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID ModeXDisableDirectDraw(
DHPDEV dhpdev)
{
}
/******************************Public*Routine******************************\
* BOOL bDdQueryModeX
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL bDdQueryModeX(
HDEV hdev,
ULONG cHeight,
ULONG* pulMode
)
{
BOOL bRet;
HANDLE hDriver;
VIDEO_NUM_MODES NumModes;
PVIDEO_MODE_INFORMATION pModes;
PVIDEO_MODE_INFORMATION pMode;
ULONG BytesReturned;
ULONG cbBuffer;
bRet = FALSE;
hDriver = UserGetVgaHandle();
if (hDriver)
{
if (!EngDeviceIoControl(hDriver,
IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES,
NULL,
0,
&NumModes,
sizeof(NumModes),
&BytesReturned))
{
cbBuffer = NumModes.NumModes * NumModes.ModeInformationLength;
pModes = (PVIDEO_MODE_INFORMATION) PALLOCMEM(cbBuffer, 'xddG');
if (pModes)
{
if (!EngDeviceIoControl(hDriver,
IOCTL_VIDEO_QUERY_AVAIL_MODES,
NULL,
0,
pModes,
cbBuffer,
&BytesReturned))
{
pMode = pModes;
while (cbBuffer != 0)
{
if ((pMode->AttributeFlags & VIDEO_MODE_COLOR) &&
(pMode->AttributeFlags & VIDEO_MODE_GRAPHICS) &&
(pMode->NumberOfPlanes == 8) &&
(pMode->BitsPerPlane == 1) &&
(pMode->VisScreenWidth == 320))
{
if (pMode->VisScreenHeight == cHeight)
{
*pulMode = pMode->ModeIndex;
bRet = TRUE;
}
}
cbBuffer -= NumModes.ModeInformationLength;
pMode = (PVIDEO_MODE_INFORMATION)
(((PUCHAR)pMode) + NumModes.ModeInformationLength);
}
}
VFREEMEM(pModes);
}
}
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL bDdEnableModeX
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL bDdEnableModeX(
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal,
ULONG cHeight
)
{
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
HANDLE hDriver;
HDEV hdev;
PDEV* ppdev;
ULONG ulMode;
VIDEO_PUBLIC_ACCESS_RANGES VideoAccessRange;
VIDEO_MEMORY FrameBufferMap;
VIDEO_MEMORY_INFORMATION FrameBufferInfo;
ULONG BytesReturned;
VIDEO_MEMORY VideoMemory;
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
hdev = peDirectDrawGlobal->hdev;
ppdev = (PDEV*) hdev;
PDEVOBJ po(hdev);
ASSERTGDI(!po.bModeXEnabled(), "ModeX already enabled");
ASSERTGDI(!po.bDisabled(), "Graphics mode not enabled");
ASSERTGDI((cHeight == 200) || (cHeight == 240), "Must be valid ModeX height");
hDriver = UserGetVgaHandle();
if (hDriver)
{
peDirectDrawGlobal->hModeX = hDriver;
// We must already be in a palette-managed mode in order to share the
// palettes:
DEVLOCKOBJ dlo(po);
if ((po.bIsPalManaged()) &&
(bDdQueryModeX(hdev, cHeight, &ulMode)))
{
{
// Disable the display:
MUTEXOBJ mutP(po.pfmPointer());
if ((po.pfnSync() != NULL) &&
(po.pSurface()->flags() & HOOK_SYNCHRONIZE))
{
(po.pfnSync())(po.dhpdev(), NULL);
}
if ((PPFNDRV(po, AssertMode) != NULL) &&
(!PPFNDRV(po, AssertMode)(po.dhpdev(), FALSE)))
{
return(FALSE);
}
}
peDirectDrawGlobal->sizlModeX.cx = 320;
peDirectDrawGlobal->sizlModeX.cy = cHeight;
if (!EngDeviceIoControl(hDriver,
IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES,
NULL,
0,
&VideoAccessRange,
sizeof(VideoAccessRange),
&BytesReturned))
{
peDirectDrawGlobal->pjModeXBase = (UCHAR*) VideoAccessRange.VirtualAddress;
if (!EngDeviceIoControl(hDriver,
IOCTL_VIDEO_SET_CURRENT_MODE,
&ulMode,
sizeof(ULONG),
NULL,
0,
&BytesReturned))
{
FrameBufferMap.RequestedVirtualAddress = NULL;
if (!EngDeviceIoControl(hDriver,
IOCTL_VIDEO_MAP_VIDEO_MEMORY,
&FrameBufferMap,
sizeof(FrameBufferMap),
&FrameBufferInfo,
sizeof(FrameBufferInfo),
&BytesReturned))
{
peDirectDrawGlobal->pjModeXScreen = (UCHAR*) FrameBufferInfo.FrameBufferBase;
po.vModeXEnabled(TRUE);
po.bDisabled(TRUE);
peDirectDrawLocal->fl |= DD_LOCAL_FLAG_MODEX_ENABLED;
peDirectDrawGlobal->pfnOldEnableDirectDraw
= ppdev->apfn[INDEX_DrvEnableDirectDraw];
peDirectDrawGlobal->pfnOldGetDirectDrawInfo
= ppdev->apfn[INDEX_DrvGetDirectDrawInfo];
peDirectDrawGlobal->pfnOldDisableDirectDraw
= ppdev->apfn[INDEX_DrvDisableDirectDraw];
ppdev->apfn[INDEX_DrvEnableDirectDraw]
= (PFN) ModeXEnableDirectDraw;
ppdev->apfn[INDEX_DrvGetDirectDrawInfo]
= (PFN) ModeXGetDirectDrawInfo;
ppdev->apfn[INDEX_DrvDisableDirectDraw]
= (PFN) ModeXDisableDirectDraw;
// Set the VGA palette to the same values were
// on the screen:
XEPALOBJ pal(po.ppalSurf());
ModeXSetPalette(peDirectDrawGlobal,
(PALOBJ *) &pal,
0,
0,
pal.cEntries());
return(TRUE);
}
else
{
WARNING("bDdEnableModeX: IOCTL_VIDEO_MAP_MEMORY failed\n");
}
}
else
{
WARNING("bDdEnableModeX: IOCTL_VIDEO_SET_CURRENT_MODE failed\n");
}
VideoMemory.RequestedVirtualAddress = peDirectDrawGlobal->pjModeXBase;
if (EngDeviceIoControl(hDriver,
IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES,
&VideoMemory,
sizeof(VIDEO_MEMORY),
NULL,
0,
&BytesReturned))
{
WARNING("bDdEnableModeX: IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES failed\n");
}
}
else
{
WARNING("bDdEnableModeX: IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES failed\n");
}
// Reenable the display:
{
MUTEXOBJ mutP(po.pfmPointer());
if (PPFNDRV(po, AssertMode) != NULL)
{
// As modeled after bEnableDisplay, we repeat the call
// until it works:
while (!PPFNDRV(po, AssertMode)(po.dhpdev(), TRUE))
;
}
XEPALOBJ pal(po.ppalSurf());
(*PPFNDRV(po,SetPalette))(po.dhpdev(),
(PALOBJ *) &pal,
0,
0,
pal.cEntries());
}
}
}
return(FALSE);
}
/******************************Public*Routine******************************\
* VOID vDdDisableModeX
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
VOID
vDdDisableModeX(
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal
)
{
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
HDEV hdev;
PDEV* ppdev;
ULONG BytesReturned;
VIDEO_MEMORY VideoMemory;
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
hdev = peDirectDrawGlobal->hdev;
ppdev = (PDEV*) hdev;
PDEVOBJ po(hdev);
ASSERTGDI(po.bModeXEnabled(), "ModeX not enabled");
ASSERTGDI(po.bDisabled(), "Graphics mode enabled");
ASSERTGDI(peDirectDrawLocal->fl & DD_LOCAL_FLAG_MODEX_ENABLED,
"vDdDisableModeX: object isn't one that owns ModeX");
if (EngDeviceIoControl(peDirectDrawGlobal->hModeX,
IOCTL_VIDEO_RESET_DEVICE,
NULL,
0,
NULL,
0,
&BytesReturned))
{
WARNING("vDdDisableModeX: IOCTL_VIDEO_RESET_DEVICE failed\n");
}
VideoMemory.RequestedVirtualAddress = peDirectDrawGlobal->pjModeXScreen;
if (EngDeviceIoControl(peDirectDrawGlobal->hModeX,
IOCTL_VIDEO_UNMAP_VIDEO_MEMORY,
&VideoMemory,
sizeof(VIDEO_MEMORY),
NULL,
0,
&BytesReturned))
{
WARNING("vDdDisableModeX: IOCTL_VIDEO_UNMAP_VIDEO_MEMORY failed\n");
}
VideoMemory.RequestedVirtualAddress = peDirectDrawGlobal->pjModeXBase;
if (EngDeviceIoControl(peDirectDrawGlobal->hModeX,
IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES,
&VideoMemory,
sizeof(VIDEO_MEMORY),
NULL,
0,
&BytesReturned))
{
WARNING("vDdDisableModeX: IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES failed\n");
}
// Need devlock to modify PDEV flags:
DEVLOCKOBJ dlo(po);
po.vModeXEnabled(FALSE);
po.bDisabled(FALSE);
peDirectDrawLocal->fl &= ~DD_LOCAL_FLAG_MODEX_ENABLED;
ppdev->apfn[INDEX_DrvEnableDirectDraw]
= peDirectDrawGlobal->pfnOldEnableDirectDraw;
ppdev->apfn[INDEX_DrvGetDirectDrawInfo]
= peDirectDrawGlobal->pfnOldGetDirectDrawInfo;
ppdev->apfn[INDEX_DrvDisableDirectDraw]
= peDirectDrawGlobal->pfnOldDisableDirectDraw;
// Reenable the display:
{
MUTEXOBJ mutP(po.pfmPointer());
if (PPFNDRV(po, AssertMode) != NULL)
{
// As modeled after bEnableDisplay, we repeat the call
// until it works:
while (!PPFNDRV(po, AssertMode)(po.dhpdev(), TRUE))
;
}
XEPALOBJ pal(po.ppalSurf());
(*PPFNDRV(po,SetPalette))(po.dhpdev(),
(PALOBJ *) &pal,
0,
0,
pal.cEntries());
}
}
/******************************Public*Routine******************************\
* BOOL NtGdiDdSetModeX
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
APIENTRY
NtGdiDdSetModeX(
HANDLE hDirectDrawLocal,
ULONG cHeight
)
{
BOOL bRet;
EDD_LOCK_DIRECTDRAW eLockDirectDraw;
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal;
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal;
bRet = FALSE;
if ((cHeight == 0) ||
(cHeight == 200) ||
(cHeight == 240))
{
peDirectDrawLocal = eLockDirectDraw.peLock(hDirectDrawLocal);
if (peDirectDrawLocal != NULL)
{
peDirectDrawGlobal = peDirectDrawLocal->peDirectDrawGlobal;
PDEVOBJ po(peDirectDrawGlobal->hdev);
// The user critical section must be acquired to make
// GreDisableDirectDraw/GreEnableDirectDraw calls.
USERCRIT usercrit;
// Either the PDEV must be enabled, or we must already be in
// ModeX for this to work:
if (!po.bDisabled() || po.bModeXEnabled())
{
// This will automatically disable the current mode, be it
// ModeX or non-ModeX:
GreDisableDirectDraw(peDirectDrawGlobal->hdev, TRUE);
bRet = TRUE;
// A height of '0' specifies that ModeX should be disabled:
if (cHeight != 0)
{
if (!po.bModeXEnabled())
{
// Switch to ModeX:
bRet = bDdEnableModeX(peDirectDrawLocal, cHeight);
}
else
{
WARNING("NtGdiDdSetModeX: Someone is already in MOdeX\n");
}
}
// Allow DirectDraw to be reenabled:
GreEnableDirectDraw(peDirectDrawGlobal->hdev);
}
}
else
{
WARNING("NtGdiDdSetModeX: Invalid or locked object\n");
}
}
else
{
WARNING("NtGdiDdSetModeX: Invalid height\n");
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL NtGdiDdQueryModeX
*
* 3-Dec-1995 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
BOOL
APIENTRY
NtGdiDdQueryModeX(
HDC hdc
)
{
BOOL bRet;
ULONG ulMode;
bRet = FALSE;
XDCOBJ dco(hdc);
if (dco.bValid())
{
bRet = bDdQueryModeX(dco.hdev(), 200, &ulMode)
&& bDdQueryModeX(dco.hdev(), 240, &ulMode);
dco.vUnlockFast();
}
return(bRet);
}