mirror of https://github.com/lianthony/NT4.0
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
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);
|
|
}
|