Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1213 lines
39 KiB

/******************************Module*Header*******************************\
* Module Name: d3d.cxx
*
* Contains all of GDI's private Direct3D APIs.
*
* Created: 04-Jun-1996
* Author: Drew Bliss [drewb]
*
* Copyright (c) 1995-1999 Microsoft Corporation
*
\**************************************************************************/
#include "precomp.hxx"
// Minimum size of DrawPrimitive buffer associated with a context.
#define MIN_PRIM_BUFFER_SIZE (1 << 14)
// Maximum
#define MAX_PRIM_BUFFER_SIZE (1 << 20)
// Default
#define DEF_PRIM_BUFFER_SIZE (1 << 16)
// Alignment requirement for the DrawPrim buffer. Must be a power of two.
#define DP_BUFFER_ALIGN 32
// Maximum number of vertices considered legal.
#define MAX_VERTEX_COUNT 0x10000
// Maximum number of indices considered legal.
#define MAX_INDEX_COUNT 0x80000
// Maximum number of clear rectangles considered legal.
#define MAX_CLEAR_RECTS 0x1000
// Maximum number of state changes per RenderState call
#define MAX_STATE_CHANGE (D3DRENDERSTATE_STIPPLEPATTERN31+1)
#ifdef D3D_ENTRIES
#define D3D_ENTRY(s) WARNING(s)
#else
#define D3D_ENTRY(s)
#endif
// Simple structure for managing DD surfaces
struct D3D_SURFACE
{
HANDLE h;
BOOL bOptional;
EDD_SURFACE* peSurf;
PDD_SURFACE_LOCAL pLcl;
};
#define INIT_D3DSURFACE(SurfaceArray, Count) \
for (int i = 0 ; i < (Count) ; i++) { \
(SurfaceArray)[i].peSurf = NULL; \
}
#define CLEANUP_D3DSURFACE(SurfaceArray, Count) \
for (int i = 0 ; i < (Count) ; i++) { \
if ((SurfaceArray)[i].peSurf) { \
DEC_EXCLUSIVE_REF_CNT((SurfaceArray)[i].peSurf); \
} \
}
// Convenience macro for parameter validation. ProbeForWrite does
// all the checks that ProbeForRead does in addition to write testing
// so it serves as a read/write check.
// Assumes DWORD alignment.
#define CAPTURE_RW_STRUCT(ptr, type) \
(ProbeForWrite(ptr, sizeof(type), sizeof(DWORD)), *(ptr))
#define CAPTURE_RD_STRUCT(ptr, type) \
(ProbeForRead(ptr, sizeof(type), sizeof(DWORD)), *(ptr))
/******************************Public*Routine******************************\
*
* D3dLockSurfaces
*
* Walks the array of surfaces, locking any with non-zero handles
*
* 1. This routine must be called with the HmgrSemaphore acquired.
* 2. INIT_D3DSURFACE must be called for pSurf parameter.
*
* History:
* Fri Jun 14 14:26:06 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL D3dLockSurfaces(int n, D3D_SURFACE *pSurf)
{
while (n-- > 0)
{
if (pSurf->h != NULL)
{
pSurf->peSurf = (EDD_SURFACE *)DdHmgLock((HDD_OBJ)pSurf->h, DD_SURFACE_TYPE, TRUE);
if (pSurf->peSurf == NULL)
{
WARNING("D3dLockSurfaces unable to lock buffer");
return FALSE;
}
if (pSurf->peSurf->bLost)
{
WARNING("D3dLockSurfaces unable to lock buffer Surface is Lost");
return FALSE;
}
pSurf->pLcl = pSurf->peSurf;
}
else if (!pSurf->bOptional)
{
WARNING("D3dLockSurfaces: NULL for mandatory surface");
return FALSE;
}
else
{
pSurf->pLcl = NULL;
}
pSurf++;
}
return TRUE;
}
/******************************Public*Routine******************************\
*
* D3dSetup
*
* Prepares the system for a call to a D3D driver
*
* History:
* Tue Jun 04 17:09:23 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
BOOL D3dSetup(EDD_DIRECTDRAW_GLOBAL* peDdGlobal,
KFLOATING_SAVE* pfsState)
{
ASSERTGDI(peDdGlobal != NULL,
"D3dSetup on NULL global\n");
if (!NT_SUCCESS(KeSaveFloatingPointState(pfsState)))
{
WARNING("D3dSetup: Unable to save FP state\n");
return FALSE;
}
DxEngLockHdev(peDdGlobal->hdev);
return TRUE;
}
/******************************Public*Routine******************************\
*
* D3dCleanup
*
* Cleans up after a D3D driver calls
*
* History:
* Tue Jun 04 17:10:21 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
void D3dCleanup(EDD_DIRECTDRAW_GLOBAL* peDdGlobal,
KFLOATING_SAVE* pfsState)
{
DxEngUnlockHdev(peDdGlobal->hdev);
KeRestoreFloatingPointState(pfsState);
}
/******************************Public*Routine******************************\
*
* D3dLockContext
*
* Prepares the system for a call to a D3D driver with a driver context
*
* This routine must be called with the HmgrSemaphore acquired
*
* History:
* Tue Jun 04 17:09:23 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
D3DNTHAL_CONTEXT *D3dLockContext(KFLOATING_SAVE *pfsState,
ULONG_PTR *pdwhContext)
{
D3DNTHAL_CONTEXT *pdhctx;
pdhctx = (D3DNTHAL_CONTEXT *)DdHmgLock((HDD_OBJ)*pdwhContext, D3D_HANDLE_TYPE, TRUE);
// release handle manager lock.
DdHmgReleaseHmgrSemaphore();
if (pdhctx == NULL)
{
WARNING("D3dLockContext unable to lock context");
return NULL;
}
// Before we access inside D3DCONTEXT.peDdGlobal, hold shared devlock,
// since peDdGlobal can be changed during video mode change.
DxEngLockShareSem();
if (pdhctx->dwType != DNHO_CONTEXT)
{
WARNING("D3dLockContext: Valid handle not a context");
goto Error_LockContext;
}
if (pdhctx->peDdGlobal == NULL)
{
WARNING("D3dLockContext: Call on disabled object");
goto Error_LockContext;
}
ASSERTGDI(pdhctx->peDdGlobal->Miscellaneous2CallBacks.CreateSurfaceEx,
"D3dLockContext: No CreateSurfaceEx callback");
if (D3dSetup(pdhctx->peDdGlobal, pfsState))
{
*pdwhContext = pdhctx->dwDriver;
// keep holding share lock, will be released at D3dUnlockContext.
return pdhctx;
}
Error_LockContext:
DEC_EXCLUSIVE_REF_CNT(pdhctx);
DxEngUnlockShareSem();
return NULL;
}
/******************************Public*Routine******************************\
*
* D3dUnlockContext
*
* Cleans up after a D3D driver calls with D3D context
*
* History:
* Tue Apr 10 16:15:00 2001 -by- Hideyuki Nagase [hideyukn]
* Created
*
\**************************************************************************/
VOID D3dUnlockContext(D3DNTHAL_CONTEXT *pdhctx, KFLOATING_SAVE *pfsState)
{
//
// Release devlock, and restore floating point state.
//
D3dCleanup(pdhctx->peDdGlobal, pfsState);
//
// Release share devlock.
//
DxEngUnlockShareSem();
//
// Unlock context
//
DEC_EXCLUSIVE_REF_CNT(pdhctx);
}
/******************************Public*Routine******************************\
*
* D3dDeleteHandle
*
* Cleans up D3D driver context wrapper objects
*
* History:
* Tue Jun 11 17:42:25 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
DWORD D3dDeleteHandle(HANDLE hD3dHandle, ULONG_PTR dwContext,
BOOL *pbRemoved, HRESULT *phr)
{
D3DNTHAL_OBJECT *pdhobj;
D3DNTHAL_CONTEXT *pdhctx;
D3DNTHAL_CONTEXTDESTROYDATA dcdd;
D3DNTHAL_TEXTUREDESTROYDATA dtdd;
KFLOATING_SAVE fsState;
DWORD dwRet = DDHAL_DRIVER_HANDLED;
// Lock handle first.
pdhobj = (D3DNTHAL_OBJECT *) DdHmgLock((HDD_OBJ)hD3dHandle, D3D_HANDLE_TYPE, FALSE);
if (pdhobj == NULL)
{
if (pbRemoved != NULL)
{
*pbRemoved = FALSE;
}
*phr = DDERR_INVALIDOBJECT;
return (dwRet);
}
// Before we access inside D3DCONTEXT.peDdGlobal, hold shared devlock,
// since peDdGlobal can be changed during video mode change.
DxEngLockShareSem();
// Sundowndx: Needs to pass in cjBuffer as SIZE_T inorder to compiler in 64bit
SIZE_T cjBuffer = 0;
if (!D3dSetup(pdhobj->peDdGlobal, &fsState))
{
DxEngUnlockShareSem();
DEC_EXCLUSIVE_REF_CNT(pdhobj);
*phr = DDERR_OUTOFMEMORY;
return (dwRet);
}
switch(pdhobj->dwType)
{
case DNHO_CONTEXT:
// Clean up DrawPrimitive buffer.
pdhctx = (D3DNTHAL_CONTEXT *)pdhobj;
MmUnsecureVirtualMemory(pdhctx->hBufSecure);
ZwFreeVirtualMemory(NtCurrentProcess(), &pdhctx->pvBufferAlloc,
&cjBuffer, MEM_RELEASE);
// Sundowndx: need to look at the d3d structure, truncate it for now
pdhctx->cjBuffer = (ULONG)cjBuffer;
// Call driver.
dcdd.dwhContext = pdhobj->dwDriver;
dwRet = pdhobj->peDdGlobal->D3dCallBacks.ContextDestroy(&dcdd);
*phr = dcdd.ddrval;
break;
case DNHO_TEXTURE:
dtdd.dwhContext = dwContext;
dtdd.dwHandle = pdhobj->dwDriver;
dwRet = pdhobj->peDdGlobal->D3dCallBacks.TextureDestroy(&dtdd);
*phr = dtdd.ddrval;
break;
}
// Now Remove handle from handle manager.
PVOID pv = DdHmgRemoveObject((HDD_OBJ)hD3dHandle, 1, 0, TRUE, D3D_HANDLE_TYPE);
// This shouldn't fail, because above DdHmgLock is succeeded.
ASSERTGDI(pv,"DdHmgRemoveObject failed D3dDeleteHandle");
// Release devlock and restore floating point state.
D3dCleanup(pdhobj->peDdGlobal, &fsState);
// Release share lock
DxEngUnlockShareSem();
// If this is last reference to DdGlobal (= GDI's PDEV), this
// will release it, so we can't call it while devlock is hold (which
// means between D3dSetup ~ D3dCleanup).
vDdDecrementReferenceCount(pdhobj->peDdGlobal);
// Delete the object.
DdFreeObject(pdhobj, D3D_HANDLE_TYPE);
if (pbRemoved != NULL)
{
*pbRemoved = TRUE;
}
return dwRet;
}
/******************************Public*Routine******************************\
*
* D3D_SIMPLE_COPY_WITH_CONTEXT
*
* Macro which creates a thunk function for D3D entry points which
* have only simple copy arguments in, a context to dereference and
* only a simple copy out.
*
* D3D_SIMPLE_DECL can be defined to add declarations.
* By default it's empty.
* D3D_SIMPLE_SETUP can be defined to add more setup code.
* By default it's empty.
* D3D_SIMPLE_WRITEBACK can be defined to add more writeback code.
* By default it's empty.
* D3D_SIMPLE_CALLBACKS is defined to the callbacks structure to look in.
* By default it's D3dCallBacks.
*
* History:
* Fri Jun 14 14:12:54 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
#define D3D_SIMPLE_DECL
#define D3D_SIMPLE_SETUP
#define D3D_SIMPLE_WRITEBACK
#define D3D_SIMPLE_CALLBACKS D3dCallBacks
#define D3D_SIMPLE_COPY_WITH_CONTEXT(Name, Type) \
DWORD APIENTRY \
DxD3d##Name(LPD3DNTHAL_##Type##DATA pdata) \
{ \
D3DNTHAL_##Type##DATA data; \
KFLOATING_SAVE fsState; \
DWORD dwRet; \
D3DNTHAL_CONTEXT* pdhctx; \
D3D_SIMPLE_DECL \
\
D3D_ENTRY("DxD3d" #Name); \
\
dwRet = DDHAL_DRIVER_NOTHANDLED; \
\
__try \
{ \
data = CAPTURE_RW_STRUCT(pdata, D3DNTHAL_##Type##DATA); \
} \
__except(EXCEPTION_EXECUTE_HANDLER) \
{ \
WARNING("DxD3d" #Name " unable to access argument"); \
return dwRet; \
} \
\
DdHmgAcquireHmgrSemaphore(); /* will be released inside D3dLockContext */ \
\
pdhctx = D3dLockContext(&fsState, &data.dwhContext); \
if (pdhctx == NULL) \
{ \
return dwRet; \
} \
\
D3D_SIMPLE_SETUP \
\
if (pdhctx->peDdGlobal->bSuspended) \
{ \
data.ddrval = DDERR_SURFACELOST; \
} \
else \
{ \
if (pdhctx->peDdGlobal->D3D_SIMPLE_CALLBACKS.##Name) \
{ \
dwRet = pdhctx->peDdGlobal->D3D_SIMPLE_CALLBACKS.##Name(&data);\
} \
else \
{ \
WARNING("DxD3d" #Name " call not present!"); \
} \
} \
\
D3dUnlockContext(pdhctx, &fsState); \
\
__try \
{ \
pdata->ddrval = data.ddrval; \
D3D_SIMPLE_WRITEBACK \
} \
__except(EXCEPTION_EXECUTE_HANDLER) \
{ \
WARNING("DxD3d" #Name " unable to write back arguments"); \
} \
\
return dwRet; \
}
/******************************Public*Routine******************************\
*
* D3D_DELETE_HANDLE
*
* Macro for routines which destroy a handle-managed object.
*
* History:
* Wed Oct 23 19:32:11 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
#define D3D_DELETE_HANDLE(Name, Type, Field) \
DWORD APIENTRY \
DxD3d##Name##Destroy(LPD3DNTHAL_##Type##DESTROYDATA pdata) \
{ \
DWORD dwRet; \
HANDLE hD3dHandle; \
HRESULT hr; \
\
D3D_ENTRY("DxD3d" #Name "Destroy"); \
\
__try \
{ \
ProbeForWrite(pdata, sizeof(D3DNTHAL_##Type##DESTROYDATA), \
sizeof(DWORD)); \
hD3dHandle = (HANDLE)pdata->Field; \
} \
__except(EXCEPTION_EXECUTE_HANDLER) \
{ \
WARNING("DxD3d" #Name "Destroy unable to access argument"); \
return DDHAL_DRIVER_NOTHANDLED; \
} \
\
dwRet = D3dDeleteHandle(hD3dHandle, 0, (BOOL *)NULL, &hr); \
\
__try \
{ \
pdata->ddrval = hr; \
} \
__except(EXCEPTION_EXECUTE_HANDLER) \
{ \
WARNING("DxD3d" #Name "Destroy unable to write back arguments"); \
} \
\
return dwRet; \
}
/******************************Public*Routine******************************\
*
* DxD3dContextCreate
*
* History:
* Tue Jun 04 13:05:18 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
DWORD APIENTRY
DxD3dContextCreate(HANDLE hDirectDrawLocal,
HANDLE hSurfColor,
HANDLE hSurfZ,
D3DNTHAL_CONTEXTCREATEI *pdcci)
{
LPD3DNTHAL_CONTEXTCREATEDATA pdccd;
D3DNTHAL_CONTEXTCREATEDATA dccd;
KFLOATING_SAVE fsState;
DWORD dwRet;
HANDLE hCleanup = 0;
EDD_DIRECTDRAW_LOCAL* peDdLocal;
EDD_LOCK_DIRECTDRAW eLockDd;
EDD_DIRECTDRAW_GLOBAL* peDdGlobal;
D3D_SURFACE dsurf[2];
NTSTATUS nts;
SIZE_T cjBuffer;
D3DNTHAL_CONTEXT* pdhctx = NULL;
PVOID pvBuffer = NULL;
PVOID pvBufRet = NULL;
HANDLE hBufSecure = NULL;
ULONG_PTR Interface;
D3D_ENTRY("DxD3dContextCreate");
ASSERTGDI(FIELD_OFFSET(D3DNTHAL_CONTEXTCREATEI, pvBuffer) ==
sizeof(D3DNTHAL_CONTEXTCREATEDATA),
"D3DNTHAL_CONTEXTCREATEI out of sync\n");
pdccd = (LPD3DNTHAL_CONTEXTCREATEDATA)pdcci;
dwRet = DDHAL_DRIVER_NOTHANDLED;
__try
{
ProbeForWrite(pdcci, sizeof(D3DNTHAL_CONTEXTCREATEI), sizeof(DWORD));
dccd.dwPID = pdccd->dwPID;
dccd.dwhContext = pdccd->dwhContext;
dccd.ddrval = pdccd->ddrval;
cjBuffer = pdcci->cjBuffer;
Interface = pdccd->dwhContext;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("DxD3dContextCreate unable to access argument");
return dwRet;
}
if (cjBuffer == 0)
{
cjBuffer = DEF_PRIM_BUFFER_SIZE;
}
else if (cjBuffer < MIN_PRIM_BUFFER_SIZE ||
cjBuffer > MAX_PRIM_BUFFER_SIZE)
{
WARNING("DxD3dContextCreate: illegal prim buffer size");
return dwRet;
}
peDdLocal = eLockDd.peLock(hDirectDrawLocal);
if (peDdLocal == NULL)
{
WARNING("DxD3dContextCreate unable to lock hDdLocal");
return dwRet;
}
peDdGlobal = peDdLocal->peDirectDrawGlobal;
INIT_D3DSURFACE(dsurf, 2);
dsurf[0].h = hSurfColor;
dsurf[0].bOptional = FALSE;
dsurf[1].h = hSurfZ;
dsurf[1].bOptional = TRUE;
DdHmgAcquireHmgrSemaphore();
if (!D3dLockSurfaces(2, dsurf))
{
DdHmgReleaseHmgrSemaphore();
goto Exit_CreateContext;
}
DdHmgReleaseHmgrSemaphore();
pdhctx = (D3DNTHAL_CONTEXT *)DdHmgAlloc(sizeof(D3DNTHAL_CONTEXT),
D3D_HANDLE_TYPE, HMGR_ALLOC_LOCK);
if (pdhctx == NULL)
{
WARNING("DxD3dContextCreate unable to alloc handle");
goto Exit_CreateContext;
}
hCleanup = pdhctx->hHmgr;
// Allocate and lock DrawPrimitive buffer space. We want the
// buffer to be aligned on a large boundary so we alter the
// pointer to return to be aligned. Note that we do not overallocate
// since we don't want the extra alignment space to push the allocation
// into another page. We're returning a size anyway so we can
// get away with this transparently.
nts = ZwAllocateVirtualMemory(NtCurrentProcess(), &pvBuffer,
0, &cjBuffer, MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE);
if (!NT_SUCCESS(nts))
{
goto Exit_CreateContext;
}
hBufSecure = MmSecureVirtualMemory(pvBuffer, cjBuffer, PAGE_READWRITE);
if (hBufSecure == NULL)
{
goto Exit_CreateContext;
}
if (!D3dSetup(peDdGlobal, &fsState))
{
goto Exit_CreateContext;
}
// CreateSurfaceEx callback must exist for DX7 or greater drivers
if (!peDdGlobal->Miscellaneous2CallBacks.CreateSurfaceEx)
{
D3dCleanup(peDdGlobal, &fsState);
goto Exit_CreateContext;
}
dccd.lpDDLcl = peDdLocal;
dccd.lpDDS = dsurf[0].pLcl;
dccd.lpDDSZ = dsurf[1].pLcl;
if (peDdGlobal->D3dCallBacks.ContextCreate)
{
dwRet = peDdGlobal->D3dCallBacks.ContextCreate(&dccd);
}
else
{
WARNING("DxD3dContextCreate: ContextCreate callback not found");
}
if (dwRet == DDHAL_DRIVER_HANDLED &&
dccd.ddrval == DD_OK)
{
// Create a wrapper for the handle and stash the DD global in it
pdhctx->dwType = DNHO_CONTEXT;
pdhctx->dwDriver = dccd.dwhContext;
pdhctx->peDdGlobal = peDdGlobal;
pdhctx->peDdLocal = peDdLocal;
pdhctx->hSurfColor = hSurfColor;
pdhctx->hSurfZ = hSurfZ;
pdhctx->hBufSecure = hBufSecure;
// Save the real pointer for freeing and return an aligned pointer
// rather than the raw pointer.
pdhctx->pvBufferAlloc = pvBuffer;
pvBufRet = (PVOID)(((ULONG_PTR)pvBuffer+DP_BUFFER_ALIGN-1) &
~(DP_BUFFER_ALIGN-1));
pdhctx->pvBufferAligned = pvBufRet;
pdhctx->cjBuffer = (ULONG)cjBuffer;
// Subtract off any space used for alignment.
cjBuffer -= (DWORD)((ULONG_PTR)pvBufRet-(ULONG_PTR)pvBuffer);
// Save interface number
pdhctx->Interface = Interface;
// Null these values to deactivate cleanup code.
hBufSecure = NULL;
pvBuffer = NULL;
hCleanup = NULL;
dccd.dwhContext = (ULONG_PTR)pdhctx->hHmgr;
/* Add reference to DirectDraw driver instance so that it won't
go away during dynamic mode changes, until the object is
deleted. */
vDdIncrementReferenceCount(pdhctx->peDdGlobal);
}
// We're done with pdhctx so unlock it
DEC_EXCLUSIVE_REF_CNT(pdhctx);
D3dCleanup(peDdGlobal, &fsState);
__try
{
pdccd->dwhContext = dccd.dwhContext;
pdccd->ddrval = dccd.ddrval;
pdcci->pvBuffer = pvBufRet;
pdcci->cjBuffer = (ULONG)cjBuffer;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("DxD3dContextCreate unable to write back arguments");
/* This is an unlikely thing to occur so we don't bother cleaning
up the handle here. It will be cleaned up by the process
termination handle cleanup. */
dwRet = DDHAL_DRIVER_NOTHANDLED;
}
Exit_CreateContext:
CLEANUP_D3DSURFACE(dsurf, 2);
if (hBufSecure != NULL)
{
MmUnsecureVirtualMemory(hBufSecure);
}
if (pvBuffer != NULL)
{
// cjBuffer has to be zero to free memory.
cjBuffer = 0;
ZwFreeVirtualMemory(NtCurrentProcess(), &pvBuffer, &cjBuffer,
MEM_RELEASE);
}
if (hCleanup != NULL)
{
DdHmgFree((HDD_OBJ)hCleanup);
}
return dwRet;
}
/******************************Public*Routine******************************\
*
* DxD3dContextDestroy
*
* History:
* Tue Jun 04 13:08:43 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
D3D_DELETE_HANDLE(Context, CONTEXT, dwhContext)
/******************************Public*Routine******************************\
*
* DxD3dContextDestroyAll
*
* History:
* Tue Jun 04 13:09:04 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
DWORD APIENTRY
DxD3dContextDestroyAll(LPD3DNTHAL_CONTEXTDESTROYALLDATA pdcdad)
{
DWORD dwRet;
D3D_ENTRY("DxD3dContextDestroyAll");
__try
{
ProbeForWrite(pdcdad, sizeof(D3DNTHAL_CONTEXTDESTROYALLDATA),
sizeof(DWORD));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("DxD3dContextDestroyAll unable to access argument");
return DDHAL_DRIVER_NOTHANDLED;
}
// Having the context wrappers be handle-based should
// provide automatic process cleanup of driver contexts
// If this function does need to be passed to the driver then
// some way to get the proper DD global will need to be found
// I don't think it's necessary, though
dwRet = DDHAL_DRIVER_NOTHANDLED;
__try
{
pdcdad->ddrval = DDERR_GENERIC;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("DxD3dContextDestroyAll unable to write back arguments");
}
return dwRet;
}
/******************************Public*Routine******************************\
*
* DxD3dDrawPrimitives2
*
* History:
* Fri Jun 14 11:56:53 1996 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
DWORD APIENTRY
DxD3dDrawPrimitives2(HANDLE hCmdBuf, HANDLE hVBuf,
LPD3DNTHAL_DRAWPRIMITIVES2DATA pded,
FLATPTR* pfpVidMemCmd,
DWORD* pdwSizeCmd,
FLATPTR* pfpVidMemVtx,
DWORD* pdwSizeVtx)
{
D3DNTHAL_DRAWPRIMITIVES2DATA ded;
KFLOATING_SAVE fsState;
DWORD dwRet;
D3D_SURFACE dsurf[4];
HANDLE hSecure = NULL;
D3DNTHAL_CONTEXT* pdhctx = NULL;
D3D_ENTRY("DxD3dDrawPrimitives2");
dwRet = DDHAL_DRIVER_NOTHANDLED;
__try
{
//
// ProbeForRead and ProbeForWrite are fairly expensive. Moved the write probe
// to the bottom but we could also do a ProbeForWriteStructure here if the
// error checking needs to be the exact same semantics.
//
ded = ProbeAndReadStructure(pded, D3DNTHAL_DRAWPRIMITIVES2DATA);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("DxD3dDrawPrimitives2 unable to access argument");
return dwRet;
}
// Initialize surface array.
INIT_D3DSURFACE(dsurf, 4);
DWORD Length = ded.dwVertexLength*ded.dwVertexSize;
// Validate and secure user-mode memory if it is a user
// allocated buffer instead of a ddraw surface
if (ded.dwFlags & D3DNTHALDP2_USERMEMVERTICES)
{
// !!Assert here that hVBuf is NULL
ASSERTGDI(hVBuf == NULL,
"User allocated memory, hVBuf should be NULL\n");
if ((Length > 0) && (ded.lpVertices != NULL))
{
LPVOID Address = (LPVOID) ((LPBYTE)ded.lpVertices +
ded.dwVertexOffset);
// Secure user-mode data.
__try
{
ProbeForRead(Address, Length, sizeof(BYTE));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("DxD3dDrawPrimives2 fail to secure the vertex buffer");
goto Exit_DP2;
}
hSecure = MmSecureVirtualMemory(Address, Length, PAGE_READONLY);
if (hSecure == NULL)
{
goto Exit_DP2;
}
dsurf[0].h = hCmdBuf;
dsurf[0].bOptional = FALSE;
DdHmgAcquireHmgrSemaphore(); // will be released at D3dLockContext();
if (!D3dLockSurfaces(1, dsurf))
{
DdHmgReleaseHmgrSemaphore();
goto Exit_DP2;
}
ded.lpDDCommands = dsurf[0].pLcl;
}
else
{
goto Exit_DP2;
}
}
else
{
dsurf[0].h = hCmdBuf;
dsurf[0].bOptional = FALSE;
dsurf[1].h = hVBuf;
dsurf[1].bOptional = FALSE;
DdHmgAcquireHmgrSemaphore(); // will be released at D3dLockContext();
if (!D3dLockSurfaces(2, dsurf))
{
DdHmgReleaseHmgrSemaphore();
goto Exit_DP2;
}
ded.lpDDCommands = dsurf[0].pLcl;
ded.lpDDVertex = dsurf[1].pLcl;
// Make sure given buffer size is smaller than the actual surface size.
if (dsurf[1].peSurf && ded.dwVertexSize)
{
DWORD dwSurfaceSize = dsurf[1].peSurf->lPitch;
if (Length > dwSurfaceSize)
{
WARNING("DxD3dDrawPrimitive2 d3d.dwVertexLength is bigger than surface, trim it!!");
ded.dwVertexLength = dwSurfaceSize / ded.dwVertexSize;
}
}
}
pdhctx = D3dLockContext(&fsState, &ded.dwhContext);
if (pdhctx == NULL)
{
goto Exit_DP2;
}
// Validate that the lpdwRStates pointer is the same as the one allocated
// by the kernel during context create. The D3d runtime uses this pointer
// to receive state information from the driver.
if (ded.lpdwRStates != pdhctx->pvBufferAligned)
{
goto Exit_DP2;
}
if ((pdhctx->peDdGlobal->bSuspended) ||
((pdhctx->peDdLocal->cSurface != pdhctx->peDdLocal->cActiveSurface) &&
// We wish we could do this for all interfaces, but due to legacy app compat reasons, we can't.
// We have noticed that apps such as Dungeon Keeper II and Final Fantasy lose surfaces and
// never bother to restore them.
pdhctx->Interface >= 4))
{
#if DBG
if (pdhctx->peDdGlobal->bSuspended)
{
// WARNING("D3dDrawPrimitives2" Caller uses disabled device");
}
else if ((pdhctx->peDdLocal->cSurface != pdhctx->peDdLocal->cActiveSurface))
{
WARNING("D3dDrawPrimitives2: Cannot call driver when lost surfaces exist in the context");
}
#endif
dwRet = DDHAL_DRIVER_HANDLED;
ded.ddrval = DDERR_SURFACELOST;
}
else
{
if (pdhctx->peDdGlobal->D3dCallBacks3.DrawPrimitives2)
{
dwRet = pdhctx->peDdGlobal->D3dCallBacks3.DrawPrimitives2(&ded);
}
else
{
WARNING("DxD3dDrawPrimitives2: DrawPrimitives2 callback absent!");
}
}
__try
{
if ((dwRet == DDHAL_DRIVER_HANDLED) && (ded.ddrval == DD_OK))
{
if (ded.dwFlags & D3DNTHALDP2_SWAPCOMMANDBUFFER)
{
ProbeAndWriteStructure( pfpVidMemCmd, ded.lpDDCommands->lpGbl->fpVidMem, FLATPTR);
ProbeAndWriteStructure( pdwSizeCmd, ded.lpDDCommands->lpGbl->dwLinearSize, DWORD);
}
if ((ded.dwFlags & D3DNTHALDP2_SWAPVERTEXBUFFER) &&
!(ded.dwFlags & D3DNTHALDP2_USERMEMVERTICES))
{
ProbeAndWriteStructure( pfpVidMemVtx, ded.lpDDVertex->lpGbl->fpVidMem, FLATPTR);
ProbeAndWriteStructure( pdwSizeVtx, ded.lpDDVertex->lpGbl->dwLinearSize, DWORD);
}
}
ProbeAndWriteUlong(&pded->dwErrorOffset, ded.dwErrorOffset);
//
// Should be cleaned up as HRESULT might not allways be a ULONG
//
ProbeAndWriteLong(&pded->ddrval, ded.ddrval);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("DxD3dDrawPrimitives2 unable to write back arguments");
dwRet = DDHAL_DRIVER_NOTHANDLED;
}
Exit_DP2:
if (pdhctx)
{
D3dUnlockContext(pdhctx, &fsState);
}
CLEANUP_D3DSURFACE(dsurf, 4);
if (hSecure)
{
MmUnsecureVirtualMemory(hSecure);
}
return dwRet;
}
/******************************Public*Routine******************************\
*
* DxD3dValidateTextureStageState
*
\**************************************************************************/
#undef D3D_SIMPLE_WRITEBACK
#define D3D_SIMPLE_WRITEBACK pdata->dwNumPasses = data.dwNumPasses;
#undef D3D_SIMPLE_CALLBACKS
#define D3D_SIMPLE_CALLBACKS D3dCallBacks3
D3D_SIMPLE_COPY_WITH_CONTEXT(ValidateTextureStageState, VALIDATETEXTURESTAGESTATE)
#undef D3D_SIMPLE_WRITEBACK
#define D3D_SIMPLE_WRITEBACK
#undef D3D_SIMPLE_CALLBACKS
#define D3D_SIMPLE_CALLBACKS D3dCallBacks
/******************************Public*Routine******************************\
*
* D3DParseUnknownCommand
*
\**************************************************************************/
HRESULT CALLBACK D3DParseUnknownCommand (LPVOID lpvCommands,
LPVOID *lplpvReturnedCommand)
{
LPD3DINSTRUCTION lpInstr = (LPD3DINSTRUCTION) lpvCommands;
LPD3DPROCESSVERTICES data;
int i;
// Initialize the return address to the command's address
*lplpvReturnedCommand = lpvCommands;
switch (lpInstr->bOpcode)
{
case D3DOP_SPAN:
*lplpvReturnedCommand = (LPVOID) ((LPBYTE)lpInstr +
sizeof (D3DINSTRUCTION) +
lpInstr->wCount *
lpInstr->bSize);
return DD_OK;
case D3DNTDP2OP_VIEWPORTINFO:
*lplpvReturnedCommand = (LPVOID) ((LPBYTE)lpInstr +
sizeof(D3DINSTRUCTION) +
lpInstr->wCount *
sizeof(D3DNTHAL_DP2VIEWPORTINFO));
return DD_OK;
case D3DNTDP2OP_WINFO:
*lplpvReturnedCommand = (LPVOID) ((LPBYTE)lpInstr +
sizeof(D3DINSTRUCTION) +
lpInstr->wCount *
sizeof(D3DNTHAL_DP2WINFO));
return DD_OK;
case D3DOP_PROCESSVERTICES:
case D3DOP_MATRIXLOAD:
case D3DOP_MATRIXMULTIPLY:
case D3DOP_STATETRANSFORM:
case D3DOP_STATELIGHT:
case D3DOP_TEXTURELOAD:
case D3DOP_BRANCHFORWARD:
case D3DOP_SETSTATUS:
case D3DOP_EXIT:
return D3DNTERR_COMMAND_UNPARSED;
default:
return DDERR_GENERIC;
}
}
/******************************Public*Routine******************************\
*
* DxDdGetDriverState
*
\**************************************************************************/
DWORD APIENTRY
DxDdGetDriverState(PDD_GETDRIVERSTATEDATA pdata)
{
DD_GETDRIVERSTATEDATA data;
KFLOATING_SAVE fsState;
DWORD dwRet;
D3DNTHAL_CONTEXT* pdhctx;
HANDLE hSecure;
D3D_ENTRY("DxDdGetDriverState");
dwRet = DDHAL_DRIVER_NOTHANDLED;
__try
{
data = CAPTURE_RW_STRUCT(pdata, DD_GETDRIVERSTATEDATA);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("DxDdGetDriverState unable to access argument");
return dwRet;
}
if (data.lpdwStates == NULL)
{
WARNING("DxDdGetDriverState passed null lpdwStates");
return dwRet;
}
// Secure the usermode memory passed down to collect state data
hSecure = MmSecureVirtualMemory((LPVOID)data.lpdwStates, data.dwLength,
PAGE_READONLY);
if (hSecure == 0)
{
return dwRet;
}
DdHmgAcquireHmgrSemaphore(); // will be released inside D3dLockContext()
pdhctx = D3dLockContext(&fsState, &data.dwhContext);
if (pdhctx == NULL)
{
goto Exit_GDS;
}
// No additional validation is needed
// Assuming that GetDriverState exists in all DX7+ drivers
ASSERTGDI(pdhctx->peDdGlobal->Miscellaneous2CallBacks.GetDriverState != NULL,
"DxDdGetDriverState is not present. It is not an optional callback\n");
if (pdhctx->peDdGlobal->bSuspended)
{
data.ddRVal = DDERR_GENERIC;
}
else
{
if (pdhctx->peDdGlobal->Miscellaneous2CallBacks.GetDriverState)
{
dwRet = pdhctx->peDdGlobal->Miscellaneous2CallBacks.GetDriverState(&data);
}
else
{
WARNING("DxD3dDrawPrimitives2: GetDriverState callback absent!");
}
}
D3dUnlockContext(pdhctx, &fsState);
__try
{
pdata->ddRVal = data.ddRVal;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("DxDdGetDriverState unable to write back arguments");
}
Exit_GDS:
MmUnsecureVirtualMemory(hSecure);
return dwRet;
}