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
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;
|
|
}
|
|
|