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.
 
 
 
 
 
 

1058 lines
38 KiB

/*==========================================================================;
*
* Copyright (C) 1997 Microsoft Corporation. All Rights Reserved.
*
* File: tldevice.cpp
*
* Content: Support code for device with transformation and lighting
*
***************************************************************************/
#include "pch.cpp"
#pragma hdrstop
#include "tlhal.h"
#include "drawprim.hpp"
#include "pvvid.h"
//=====================================================================
//
// CDirect3DDevice7 interface
//
//=====================================================================
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDevice7::Init"
HRESULT CDirect3DDevice7::Init(
REFCLSID riid, LPDIRECT3DI lpD3DI, LPDIRECTDRAWSURFACE lpDDS,
IUnknown* pUnkOuter, LPUNKNOWN* lplpD3DDevice)
{
#if 0
// Stateblocks are always emulated on DX7
DWORD value = 0;
GetD3DRegValue(REG_DWORD, "EmulateStateBlocks", &value, sizeof(DWORD));
if(value == 0)
{
// All DX7 devices should support state sets
this->dwFEFlags |= D3DFE_STATESETS;
}
#endif
HRESULT ret = CDirect3DDeviceIDP2::Init(riid, lpD3DI, lpDDS, pUnkOuter, lplpD3DDevice);
if (ret != D3D_OK)
return ret;
// Do device specific initialization here
return D3D_OK;
}
//---------------------------------------------------------------------
//
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDevice7::WriteStateSetToDevice"
void CDirect3DDevice7::WriteStateSetToDevice(D3DSTATEBLOCKTYPE sbt)
{
DWORD dwDeviceHandle;
LPVOID pBuffer;
DWORD dwBufferSize;
m_pStateSets->GetDeviceBufferInfo(&dwDeviceHandle, &pBuffer, &dwBufferSize);
// If device buffer is empty we do not create the set state macro in the device
if (dwBufferSize == 0)
return;
DWORD dwByteCount = dwBufferSize + (sizeof(D3DHAL_DP2STATESET) + sizeof(D3DHAL_DP2COMMAND)) * 2;
// Check to see if there is space to add a new command for space
if (dwByteCount + dwDP2CommandLength > dwDP2CommandBufSize)
{
// Request the driver to grow the command buffer upon flush
dp2data.dwReqCommandBufSize = dwByteCount;
dp2data.dwFlags |= D3DHALDP2_REQCOMMANDBUFSIZE;
HRESULT ret = FlushStates();
dp2data.dwFlags &= ~D3DHALDP2_REQCOMMANDBUFSIZE;
if (ret != D3D_OK)
throw ret;
// Check if the driver did give us what we need or do it ourselves
ret = GrowCommandBuffer(this->lpDirect3DI, dwByteCount);
if (ret != D3D_OK)
{
D3D_ERR("Could not grow Command Buffer");
throw ret;
}
}
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bCommand = D3DDP2OP_STATESET;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
LPD3DHAL_DP2STATESET pData = (LPD3DHAL_DP2STATESET)(lpDP2CurrCommand + 1);
pData->dwOperation = D3DHAL_STATESETBEGIN;
pData->dwParam = dwDeviceHandle;
pData->sbType = sbt;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
// Copy the entire state macro to the DP2 buffer
memcpy(pData + 1, pBuffer, dwBufferSize);
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)(pData + 1) + dwBufferSize);
lpDP2CurrCommand->bCommand = D3DDP2OP_STATESET;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
pData = (LPD3DHAL_DP2STATESET)(lpDP2CurrCommand + 1);
pData->dwOperation = D3DHAL_STATESETEND;
pData->dwParam = dwDeviceHandle;
pData->sbType = sbt;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
dwDP2CommandLength += dwByteCount;
HRESULT ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in WriteStateSetToDevice");
throw ret;
}
else
{
if(this->dwFEFlags & D3DFE_LOSTSURFACES)
{
D3D_ERR("State blocks lost in WriteStateSetToDevice");
throw DDERR_SURFACELOST;
}
}
}
//---------------------------------------------------------------------
//
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDevice7::TexBltI"
HRESULT CDirect3DDevice7::TexBltI(LPDDRAWI_DDRAWSURFACE_LCL lpDst,
LPDDRAWI_DDRAWSURFACE_LCL lpSrc,
LPPOINT p, RECTL *r, DWORD dwFlags)
{
HRESULT ret = D3D_OK;
#ifdef WINNT
// WINNT allows delay create of Kernel object
// if such a create fails, we can't pass handle to driver
if(dwFEFlags & D3DFE_REALHAL)
{
if (!lpSrc->hDDSurface && !CompleteCreateSysmemSurface(lpSrc))
{
return DDERR_GENERIC;
}
if (lpDst && !lpDst->hDDSurface && !CompleteCreateSysmemSurface(lpDst))
{
return DDERR_GENERIC;
}
}
#endif
// If the driver supports the GetSysmemBltStatus call, then the driver can
// do the Blt asynchronously. In this case, set the HARDWAREOP_STARTED
// flags so that Locks and Blts to the surface(s) in concern spin until
// the async Blt is finished.
if((lpSrc->lpSurfMore->lpDD_lcl->lpDDCB->HALDDMiscellaneous.GetSysmemBltStatus != NULL)
&& (lpSrc->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
{
lpSrc->lpGbl->dwGlobalFlags |= DDRAWISURFGBL_HARDWAREOPSOURCE;
}
if (bDP2CurrCmdOP == D3DDP2OP_TEXBLT)
{ // Last instruction is a tex blt, append this one to it
if (dwDP2CommandLength + sizeof(D3DHAL_DP2TEXBLT) <= dwDP2CommandBufSize)
{
LPD3DHAL_DP2TEXBLT lpTexBlt = (LPD3DHAL_DP2TEXBLT)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt;
lpTexBlt->dwDDDestSurface = lpDst == NULL ? 0 : lpDst->lpSurfMore->dwSurfaceHandle;
lpTexBlt->dwDDSrcSurface = lpSrc->lpSurfMore->dwSurfaceHandle;
lpTexBlt->pDest = *p;
lpTexBlt->rSrc = *r;
lpTexBlt->dwFlags = dwFlags;
dwDP2CommandLength += sizeof(D3DHAL_DP2TEXBLT);
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
return ret;
}
}
// Check for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
sizeof(D3DHAL_DP2TEXBLT) > dwDP2CommandBufSize)
{
ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in TexBltI");
return ret;
}
}
// Add new renderstate instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bCommand = D3DDP2OP_TEXBLT;
bDP2CurrCmdOP = D3DDP2OP_TEXBLT;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
wDP2CurrCmdCnt = 1;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
// Add texture blt data
LPD3DHAL_DP2TEXBLT lpTexBlt = (LPD3DHAL_DP2TEXBLT)(lpDP2CurrCommand + 1);
lpTexBlt->dwDDDestSurface = lpDst == NULL ? 0 : lpDst->lpSurfMore->dwSurfaceHandle;
lpTexBlt->dwDDSrcSurface = lpSrc->lpSurfMore->dwSurfaceHandle;
lpTexBlt->pDest = *p;
lpTexBlt->rSrc = *r;
lpTexBlt->dwFlags = dwFlags;
dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TEXBLT);
return ret;
}
//---------------------------------------------------------------------
//
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDevice7::SetPriorityI"
HRESULT CDirect3DDevice7::SetPriorityI(LPDDRAWI_DDRAWSURFACE_LCL lpDst, DWORD dwPriority)
{
HRESULT ret = D3D_OK;
if (bDP2CurrCmdOP == D3DDP2OP_SETPRIORITY)
{ // Last instruction is a set priority, append this one to it
if (dwDP2CommandLength + sizeof(D3DHAL_DP2SETPRIORITY) <= dwDP2CommandBufSize)
{
LPD3DHAL_DP2SETPRIORITY lpSetPriority = (LPD3DHAL_DP2SETPRIORITY)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt;
lpSetPriority->dwDDSurface = lpDst->lpSurfMore->dwSurfaceHandle;
lpSetPriority->dwPriority = dwPriority;
dwDP2CommandLength += sizeof(D3DHAL_DP2SETPRIORITY);
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
return ret;
}
}
// Check for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
sizeof(D3DHAL_DP2SETPRIORITY) > dwDP2CommandBufSize)
{
ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in SetPriorityI");
return ret;
}
}
// Add new setpriority instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bCommand = D3DDP2OP_SETPRIORITY;
bDP2CurrCmdOP = D3DDP2OP_SETPRIORITY;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
wDP2CurrCmdCnt = 1;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
// Add texture blt data
LPD3DHAL_DP2SETPRIORITY lpSetPriority = (LPD3DHAL_DP2SETPRIORITY)(lpDP2CurrCommand + 1);
lpSetPriority->dwDDSurface = lpDst->lpSurfMore->dwSurfaceHandle;
lpSetPriority->dwPriority = dwPriority;
dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2SETPRIORITY);
return ret;
}
//---------------------------------------------------------------------
//
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDevice7::SetTexLODI"
HRESULT CDirect3DDevice7::SetTexLODI(LPDDRAWI_DDRAWSURFACE_LCL lpDst, DWORD dwLOD)
{
HRESULT ret = D3D_OK;
if (bDP2CurrCmdOP == D3DDP2OP_SETTEXLOD)
{ // Last instruction is a set LOD, append this one to it
if (dwDP2CommandLength + sizeof(D3DHAL_DP2SETTEXLOD) <= dwDP2CommandBufSize)
{
LPD3DHAL_DP2SETTEXLOD lpSetTexLOD = (LPD3DHAL_DP2SETTEXLOD)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt;
lpSetTexLOD->dwDDSurface = lpDst->lpSurfMore->dwSurfaceHandle;
lpSetTexLOD->dwLOD = dwLOD;
dwDP2CommandLength += sizeof(D3DHAL_DP2SETTEXLOD);
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
return ret;
}
}
// Check for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) +
sizeof(D3DHAL_DP2SETTEXLOD) > dwDP2CommandBufSize)
{
ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in SetTexLODI");
return ret;
}
}
// Add new set LOD instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bCommand = D3DDP2OP_SETTEXLOD;
bDP2CurrCmdOP = D3DDP2OP_SETTEXLOD;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
wDP2CurrCmdCnt = 1;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
// Add texture blt data
LPD3DHAL_DP2SETTEXLOD lpSetTexLOD = (LPD3DHAL_DP2SETTEXLOD)(lpDP2CurrCommand + 1);
lpSetTexLOD->dwDDSurface = lpDst->lpSurfMore->dwSurfaceHandle;
lpSetTexLOD->dwLOD = dwLOD;
dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2SETTEXLOD);
return ret;
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDevice7::UpdatePalette"
//---------------------------------------------------------------------
// This function should be called from PaletteUpdateNotify
//
HRESULT CDirect3DDevice7::UpdatePalette(
DWORD dwPaletteHandle,
DWORD dwStartIndex,
DWORD dwNumberOfIndices,
LPPALETTEENTRY pFirstIndex)
{
HRESULT ret = D3D_OK;
DWORD dwSizeChange=sizeof(D3DHAL_DP2COMMAND) +
sizeof(D3DHAL_DP2UPDATEPALETTE) + dwNumberOfIndices*sizeof(PALETTEENTRY);
if (bDP2CurrCmdOP == D3DDP2OP_UPDATEPALETTE)
{ // Last instruction is a tex blt, append this one to it
}
// Check for space
if (dwDP2CommandLength + dwSizeChange > dwDP2CommandBufSize)
{
ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in TexBltI");
return ret;
}
}
// Add new renderstate instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bCommand = D3DDP2OP_UPDATEPALETTE;
bDP2CurrCmdOP = D3DDP2OP_UPDATEPALETTE;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
wDP2CurrCmdCnt = 1;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
// Add texture blt data
LPD3DHAL_DP2UPDATEPALETTE lpUpdatePal = (LPD3DHAL_DP2UPDATEPALETTE)(lpDP2CurrCommand + 1);
lpUpdatePal->dwPaletteHandle=dwPaletteHandle;
lpUpdatePal->wStartIndex=(WORD)dwStartIndex;
lpUpdatePal->wNumEntries=(WORD)dwNumberOfIndices;
memcpy((LPVOID)(lpUpdatePal+1),(LPVOID)pFirstIndex,
dwNumberOfIndices*sizeof(PALETTEENTRY));
dwDP2CommandLength += dwSizeChange;
return ret;
}
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDevice7::SetPalette"
//---------------------------------------------------------------------
// This function should be called from PaletteAssociateNotify
//
HRESULT CDirect3DDevice7::SetPalette(DWORD dwPaletteHandle,
DWORD dwPaletteFlags,
DWORD dwSurfaceHandle )
{
HRESULT ret = D3D_OK;
DWORD dwSizeChange;
if (bDP2CurrCmdOP == D3DDP2OP_SETPALETTE)
{ // Last instruction is a tex blt, append this one to it
}
dwSizeChange=sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2SETPALETTE);
// Check for space
if (dwDP2CommandLength + dwSizeChange > dwDP2CommandBufSize)
{
ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in TexBltI");
return ret;
}
}
// Add new renderstate instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bCommand = D3DDP2OP_SETPALETTE;
bDP2CurrCmdOP = D3DDP2OP_UPDATEPALETTE;
lpDP2CurrCommand->bReserved = 0;
lpDP2CurrCommand->wStateCount = 1;
wDP2CurrCmdCnt = 1;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
LPD3DHAL_DP2SETPALETTE lpSetPal = (LPD3DHAL_DP2SETPALETTE)(lpDP2CurrCommand + 1);
lpSetPal->dwPaletteHandle=dwPaletteHandle;
lpSetPal->dwPaletteFlags=dwPaletteFlags;
lpSetPal->dwSurfaceHandle=dwSurfaceHandle;
dwDP2CommandLength += dwSizeChange;
return ret;
}
//---------------------------------------------------------------------
//
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDevice7::UpdateTextures"
HRESULT CDirect3DDevice7::UpdateTextures()
{
HRESULT result = D3D_OK;
DWORD dwSavedFlags = this->dwFlags;
this->dwFlags |= D3DPV_WITHINPRIMITIVE;
for (DWORD dwStage = 0; dwStage < this->dwMaxTextureBlendStages; dwStage++)
{
D3DTEXTUREHANDLE dwDDIHandle;
LPDIRECT3DTEXTUREI lpTexI = this->lpD3DMappedTexI[dwStage];
if(lpTexI)
{
if (lpTexI->InVidmem())
{
if (lpTexI->bDirty)
{
CLockD3DST lockObject(this, DPF_MODNAME, REMIND("")); // we access DDraw gbl in CopySurface
// 0xFFFFFFFF is equivalent to ALL_FACES, but in addition indicates to CopySurface
// that this is a sysmem -> vidmem transfer.
result = CopySurface(lpTexI->lpDDS,NULL,lpTexI->lpDDSSys,NULL,0xFFFFFFFF);
if (DD_OK != result)
{
D3D_ERR("Error copying surface while updating textures");
goto l_exit;
}
else
{
lpTexI->bDirty=FALSE;
D3D_INFO(4,"UpdateTextures: Dirty texture updated");
}
}
}
else
{
if(lpTexI->D3DManaged())
{
// Not in vidmem, so we need to call GetTextureDDIHandle
m_dwStageDirty |= (1 << dwStage);
}
}
if (m_dwStageDirty & (1 << dwStage))
{
result = GetTextureDDIHandle(lpTexI, &dwDDIHandle);
if (result != D3D_OK)
{
D3D_ERR("Failed to get texture handle");
goto l_exit;
}
BatchTexture(((LPDDRAWI_DDRAWSURFACE_INT)lpTexI->lpDDS)->lpLcl);
m_dwStageDirty &= ~(1 << dwStage); // reset stage dirty
}
else
{
continue; // Ok, then nothing needs to be done further
}
}
else if (m_dwStageDirty & (1 << dwStage))
{
dwDDIHandle = 0; //tell driver to disable this texture
m_dwStageDirty &= ~(1 << dwStage); // reset stage dirty
}
else
{
continue;
}
result = SetTSSI(dwStage, (D3DTEXTURESTAGESTATETYPE)D3DTSS_TEXTUREMAP, dwDDIHandle);
if(result != D3D_OK)
{
D3D_ERR("Failed to batch set texture instruction");
goto l_exit;
}
// Update runtime copy of state.
this->tsstates[dwStage][D3DTSS_TEXTUREMAP] = dwDDIHandle;
}
l_exit:
this->dwFlags = dwSavedFlags;
return result;
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDevice7::GetTextureDDIHandle"
HRESULT CDirect3DDevice7::GetTextureDDIHandle(LPDIRECT3DTEXTUREI lpTexI, D3DTEXTUREHANDLE *phTex)
{
if(lpTexI->D3DManaged())
{
if(!lpTexI->InVidmem())
{
HRESULT ret = lpDirect3DI->lpTextureManager->allocNode(lpTexI, this);
if (D3D_OK != ret)
{
D3D_ERR("Failed to create video memory surface");
return ret;
}
}
lpDirect3DI->lpTextureManager->TimeStamp(lpTexI);
}
*phTex = lpTexI->m_hTex;
return D3D_OK;
}
void CDirect3DDevice7::SetRenderTargetI(LPDIRECTDRAWSURFACE pRenderTarget, LPDIRECTDRAWSURFACE pZBuffer)
{
LPD3DHAL_DP2SETRENDERTARGET pData;
pData = (LPD3DHAL_DP2SETRENDERTARGET)GetHalBufferPointer(D3DDP2OP_SETRENDERTARGET, sizeof(*pData));
pData->hRenderTarget = ((LPDDRAWI_DDRAWSURFACE_INT)pRenderTarget)->lpLcl->lpSurfMore->dwSurfaceHandle;
if (pZBuffer)
pData->hZBuffer = ((LPDDRAWI_DDRAWSURFACE_INT)pZBuffer)->lpLcl->lpSurfMore->dwSurfaceHandle;
else
pData->hZBuffer = 0;
// Flush before switching RenderTarget..
HRESULT ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to FlushStates in SetRenderTarget");
throw ret;
}
}
void CDirect3DDevice7::SetRenderTargetINoFlush(LPDIRECTDRAWSURFACE pRenderTarget, LPDIRECTDRAWSURFACE pZBuffer)
{
LPD3DHAL_DP2SETRENDERTARGET pData;
pData = (LPD3DHAL_DP2SETRENDERTARGET)GetHalBufferPointer(D3DDP2OP_SETRENDERTARGET, sizeof(*pData));
pData->hRenderTarget = ((LPDDRAWI_DDRAWSURFACE_INT)pRenderTarget)->lpLcl->lpSurfMore->dwSurfaceHandle;
if (pZBuffer)
pData->hZBuffer = ((LPDDRAWI_DDRAWSURFACE_INT)pZBuffer)->lpLcl->lpSurfMore->dwSurfaceHandle;
else
pData->hZBuffer = 0;
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDevice7::CanDoTexBlt"
bool CDirect3DDevice7::CanDoTexBlt(LPDDRAWI_DDRAWSURFACE_LCL lpDDSSrcSubFace_lcl,
LPDDRAWI_DDRAWSURFACE_LCL lpDDSDstSubFace_lcl)
{
if(dwFEFlags & D3DFE_REALHAL)
{
DWORD &srccaps = lpDDSSrcSubFace_lcl->ddsCaps.dwCaps;
DWORD &dstcaps = lpDDSDstSubFace_lcl->ddsCaps.dwCaps;
DDCORECAPS &ddcaps = ((LPDDRAWI_DIRECTDRAW_INT)(lpDirect3DI->lpDD7))->lpLcl->lpGbl->ddCaps;
if(srccaps & DDSCAPS_VIDEOPORT)
{
return false;
}
DDPIXELFORMAT &srcpf = PixelFormat(lpDDSSrcSubFace_lcl);
DDPIXELFORMAT &dstpf = PixelFormat(lpDDSDstSubFace_lcl);
if(!MatchDDPIXELFORMAT(&srcpf, &dstpf))
{
return false;
}
else if((srcpf.dwFlags & DDPF_FOURCC) && srcpf.dwFourCC == dstpf.dwFourCC &&
!(ddcaps.dwCaps2 & DDCAPS2_COPYFOURCC))
{
return false;
}
if(ddcaps.dwCaps2 & DDCAPS2_NONLOCALVIDMEMCAPS)
{
if(srccaps & DDSCAPS_SYSTEMMEMORY)
{
if((dstcaps & DDSCAPS_NONLOCALVIDMEM) && (this->d3dDevDesc.dwDevCaps & D3DDEVCAPS_CANBLTSYSTONONLOCAL))
{
return true;
}
else if((dstcaps & DDSCAPS_LOCALVIDMEM) && (ddcaps.dwSVBCaps & DDCAPS_BLT))
{
return true;
}
else
{
return false;
}
}
else if(srccaps & DDSCAPS_NONLOCALVIDMEM)
{
LPDDNONLOCALVIDMEMCAPS &lpnlvcaps = ((LPDDRAWI_DIRECTDRAW_INT)lpDirect3DI->lpDD7)->lpLcl->lpGbl->lpddNLVCaps;
DDASSERT(lpnlvcaps);
if((dstcaps & DDSCAPS_LOCALVIDMEM) && (lpnlvcaps->dwNLVBCaps & DDCAPS_BLT))
{
return true;
}
else
{
return false;
}
}
else if(srccaps & DDSCAPS_LOCALVIDMEM)
{
if((dstcaps & DDSCAPS_LOCALVIDMEM) && (ddcaps.dwCaps & DDCAPS_BLT))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
if(srccaps & DDSCAPS_SYSTEMMEMORY)
{
if((dstcaps & DDSCAPS_VIDEOMEMORY) && (ddcaps.dwSVBCaps & DDCAPS_BLT))
{
return true;
}
else
{
return false;
}
}
else if(srccaps & DDSCAPS_VIDEOMEMORY)
{
if((dstcaps & DDSCAPS_VIDEOMEMORY) && (ddcaps.dwCaps & DDCAPS_BLT))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
}
return false;
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDevice7::ClearI"
void CDirect3DDevice7::ClearI(DWORD dwFlags, DWORD clrCount, D3DCOLOR dwColor, D3DVALUE dvZ, DWORD dwStencil)
{
DWORD dwCommandSize = sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2CLEAR) + sizeof(RECT) * (clrCount - 1);
// Check to see if there is space to add a new command for space
if (dwCommandSize + dwDP2CommandLength > dwDP2CommandBufSize)
{
HRESULT ret = FlushStates();
if (ret != D3D_OK)
{
D3D_ERR("Error trying to render batched commands in CDirect3DDevice7::ClearI");
throw ret;
}
}
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands +
dwDP2CommandLength + dp2data.dwCommandOffset);
lpDP2CurrCommand->bCommand = D3DDP2OP_CLEAR;
bDP2CurrCmdOP = D3DDP2OP_CLEAR;
lpDP2CurrCommand->bReserved = 0;
wDP2CurrCmdCnt = (WORD)clrCount;
lpDP2CurrCommand->wStateCount = wDP2CurrCmdCnt;
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand);
dwDP2CommandLength += dwCommandSize;
// Write data
LPD3DHAL_DP2CLEAR pData = (LPD3DHAL_DP2CLEAR)(lpDP2CurrCommand + 1);
pData->dwFlags = dwFlags;
pData->dwFillColor = dwColor;
pData->dvFillDepth = dvZ;
pData->dwFillStencil = dwStencil;
memcpy(pData->Rects, clrRects, clrCount * sizeof(D3DRECT));
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDevice7::GetInfo"
HRESULT D3DAPI CDirect3DDevice7::GetInfo(DWORD dwDevInfoID, LPVOID pDevInfoStruct, DWORD dwSize)
{
CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
// Release in the destructor
if (!VALID_DIRECT3DDEVICE_PTR(this))
{
D3D_ERR( "Invalid DIRECT3DDEVICE7 pointer" );
return DDERR_INVALIDOBJECT;
}
if (dwSize == 0 || !VALID_D3DDEVINFOSTRUCT_PTR(pDevInfoStruct, dwSize))
{
D3D_ERR( "Invalid structure pointer or size" );
return DDERR_INVALIDOBJECT;
}
memset(pDevInfoStruct, 0, dwSize);
#if DBG
if (this->dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE)
{
D3D_WARN( 2, "GetInfo called within a scene" );
}
if( this->pfnGetDriverState == NULL )
{
D3D_ERR( "GetDriverState not implemented by the driver" );
DDASSERT( this->pfnGetDriverState );
}
#endif
try
{
switch(dwDevInfoID)
{
#if COLLECTSTATS
case D3DDEVINFOID_TEXTUREMANAGER:
if(!(((LPDDRAWI_DIRECTDRAW_INT)(this->lpDirect3DI->lpDD7))->lpLcl->lpGbl->ddCaps.dwCaps2 & DDCAPS2_CANMANAGETEXTURE))
{
lpDirect3DI->lpTextureManager->GetStats((LPD3DDEVINFO_TEXTUREMANAGER)pDevInfoStruct);
return D3D_OK;
}
break;
#else
case D3DDEVINFOID_TEXTUREMANAGER:
D3D_WARN( 0, "Stats not collected in this build" );
return S_FALSE;
#endif
default:
if(GetInfoInternal(dwDevInfoID, pDevInfoStruct, dwSize))
return D3D_OK;
}
HRESULT hr = FlushStates();
if(hr != D3D_OK)
{
D3D_ERR("Error flushing device");
return hr;
}
}
catch(HRESULT ret)
{
memset(pDevInfoStruct, 0, dwSize);
return ret;
}
HRESULT hr;
DDHAL_GETDRIVERSTATEDATA dsd;
dsd.dwFlags = dwDevInfoID;
dsd.dwhContext = this->dwhContext;
dsd.lpdwStates = (LPDWORD)pDevInfoStruct;
dsd.dwLength = dwSize;
LOCK_HAL(hr, this);
hr = this->pfnGetDriverState(&dsd);
UNLOCK_HAL(this);
if (hr != DDHAL_DRIVER_HANDLED)
{
D3D_WARN( 1, "Device information query unsupported" );
memset(pDevInfoStruct, 0, dwSize);
return S_FALSE;
}
else if (dsd.ddRVal != DD_OK)
{
D3D_INFO(1,"Driver failed GetInfo");
memset(pDevInfoStruct, 0, dwSize);
return E_FAIL;
}
return D3D_OK;
}
//=====================================================================
//
// CDirect3DDeviceTL interface
//
//=====================================================================
CDirect3DDeviceTL::CDirect3DDeviceTL()
{
deviceType = D3DDEVTYPE_DX7TLHAL;
m_rsMax = D3D_MAXRENDERSTATES;
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceTL::Init"
HRESULT CDirect3DDeviceTL::Init(
REFCLSID riid, LPDIRECT3DI lpD3DI, LPDIRECTDRAWSURFACE lpDDS,
IUnknown* pUnkOuter, LPUNKNOWN* lplpD3DDevice)
{
this->dwFEFlags |= D3DFE_TLHAL;
#if 0
// Stateblocks are always emulated on DX7
DWORD value = 0;
GetD3DRegValue(REG_DWORD, "EmulateStateBlocks", &value, sizeof(DWORD));
if(value == 0)
{
// All DX7 devices should support state sets
this->dwFEFlags |= D3DFE_STATESETS;
}
#endif
HRESULT ret = CDirect3DDevice7::Init(riid, lpD3DI, lpDDS, pUnkOuter, lplpD3DDevice);
if (ret != D3D_OK)
return ret;
// Do device specific initialization here
return D3D_OK;
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceTL::MaterialChanged"
void CDirect3DDeviceTL::MaterialChanged()
{
// Update front-end state (for ProcessVertices calls)
DIRECT3DDEVICEI::MaterialChanged();
// Driver should not be called because it will execute the macro)
if (this->dwFEFlags & D3DFE_EXECUTESTATEMODE)
return;
LPD3DHAL_DP2SETMATERIAL pData;
pData = (LPD3DHAL_DP2SETMATERIAL)GetHalBufferPointer(D3DDP2OP_SETMATERIAL, sizeof(*pData));
*pData = this->lighting.material;
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceTL::SetClipPlaneI"
void CDirect3DDeviceTL::SetClipPlaneI(DWORD dwPlaneIndex, D3DVALUE* pPlaneEquation)
{
// Update front-end state (for DrawPrimitiveStrided calls)
DIRECT3DDEVICEI::SetClipPlaneI(dwPlaneIndex, pPlaneEquation);
// Driver should not be called because it will execute the macro)
if (this->dwFEFlags & D3DFE_EXECUTESTATEMODE)
return;
#if DBG
if (dwPlaneIndex >= this->transform.dwMaxUserClipPlanes)
{
D3D_WARN(1, "Device does not support that many clipping planes");
return;
}
#endif
LPD3DHAL_DP2SETCLIPPLANE pData;
pData = (LPD3DHAL_DP2SETCLIPPLANE)GetHalBufferPointer(D3DDP2OP_SETCLIPPLANE, sizeof(*pData));
pData->dwIndex = dwPlaneIndex;
pData->plane[0] = pPlaneEquation[0];
pData->plane[1] = pPlaneEquation[1];
pData->plane[2] = pPlaneEquation[2];
pData->plane[3] = pPlaneEquation[3];
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceTL::LightChanged"
void CDirect3DDeviceTL::LightChanged(DWORD dwLightIndex)
{
// Update front-end state (for ProcessVertices calls)
LPDIRECT3DLIGHTI pLight = &m_pLights[dwLightIndex];
BOOL bValid = pLight->Valid(); // Valid bit will be set in LightChanged
DIRECT3DDEVICEI::LightChanged(dwLightIndex);
// If this is first time we set the light data, we call HALL to create
// light. HAL could grow the internal light list at this time
if (!bValid)
{
LPD3DHAL_DP2CREATELIGHT pData;
pData = (LPD3DHAL_DP2CREATELIGHT)GetHalBufferPointer(D3DDP2OP_CREATELIGHT, sizeof(*pData));
pData->dwIndex = dwLightIndex;
pLight->m_LightI.flags |= D3DLIGHTI_VALID;
}
if (this->dwFEFlags & D3DFE_EXECUTESTATEMODE)
return;
LPD3DHAL_DP2SETLIGHT pData;
pData = (LPD3DHAL_DP2SETLIGHT)GetHalBufferPointer(D3DDP2OP_SETLIGHT,
sizeof(*pData)+sizeof(D3DLIGHT7));
pData->dwIndex = dwLightIndex;
pData->dwDataType = D3DHAL_SETLIGHT_DATA;
*(D3DLIGHT7 *)((LPBYTE)pData + sizeof(D3DHAL_DP2SETLIGHT)) =
pLight->m_Light;
}
//---------------------------------------------------------------------
// Nothing to do here, because render state is used to enable/disable
// lights
//
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceTL::LightEnableI"
void CDirect3DDeviceTL::LightEnableI(DWORD dwLightIndex, BOOL bEnable)
{
DIRECT3DDEVICEI::LightEnableI(dwLightIndex, bEnable);
if (!(this->dwFEFlags & D3DFE_EXECUTESTATEMODE))
{
LPD3DHAL_DP2SETLIGHT pData;
pData = (LPD3DHAL_DP2SETLIGHT)GetHalBufferPointer(D3DDP2OP_SETLIGHT, sizeof(*pData));
pData->dwIndex = dwLightIndex;
if (bEnable)
pData->dwDataType = D3DHAL_SETLIGHT_ENABLE;
else
pData->dwDataType = D3DHAL_SETLIGHT_DISABLE;
}
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceTL::SetTransformI"
void CDirect3DDeviceTL::SetTransformI(D3DTRANSFORMSTATETYPE type,
LPD3DMATRIX pMat)
{
DDASSERT(pMat != NULL);
DIRECT3DDEVICEI::SetTransformI(type, pMat);
if (!(this->dwFEFlags & D3DFE_EXECUTESTATEMODE))
{
LPD3DHAL_DP2SETTRANSFORM pData;
pData = (LPD3DHAL_DP2SETTRANSFORM)GetHalBufferPointer(D3DDP2OP_SETTRANSFORM, sizeof(*pData));
pData->xfrmType = type;
pData->matrix = *pMat;
}
}
//---------------------------------------------------------------------
// ProcessPrimitive processes indexed and non-indexed primitives
// as defined by "op"
// It is assumed that only untransformed vertices are passed to this function
//
// op = __PROCPRIMOP_NONINDEXEDPRIM by default
//
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceTL::ProcessPrimitive"
HRESULT CDirect3DDeviceTL::ProcessPrimitive(__PROCPRIMOP op)
{
HRESULT ret;
#if DBG
// Do some validation
if (!FVF_TRANSFORMED(this->dwVIDIn))
{
if (this->rstates[D3DRENDERSTATE_VERTEXBLEND])
{
if(this->rstates[D3DRENDERSTATE_VERTEXBLEND] + 1 > this->d3dDevDesc.wMaxVertexBlendMatrices)
{
D3D_WARN(1, "Device does not support that many blend weights");
}
}
}
#endif
this->dwVIDOut = this->dwVIDIn;
if (this->dwDeviceFlags & D3DDEV_STRIDE)
{
DWORD dwTexCoordSizeDummy[8];
DWORD dwFVF = this->dwVIDIn;
DWORD dwPositionSize = GetPositionSizeFVF(dwFVF);
DWORD dwVertexSize = GetVertexSizeFVF(dwFVF) +
ComputeTextureCoordSize(dwFVF, dwTexCoordSizeDummy);
this->dwOutputSize = dwVertexSize;
this->dwVertexPoolSize = this->dwNumVertices * dwVertexSize;
if (this->TLVbuf_Grow(this->dwVertexPoolSize, true) != D3D_OK)
{
D3D_ERR( "Could not grow TL vertex buffer" );
return DDERR_OUTOFMEMORY;
}
ret = this->StartPrimVB(this->TLVbuf_GetVBI(), 0);
if (ret != D3D_OK)
return ret;
D3DVALUE *p = (D3DVALUE*)this->TLVbuf_GetAddress();
for (DWORD n = this->dwNumVertices; n; n--)
{
// XYZ and wheights
memcpy(p, this->position.lpvData, dwPositionSize);
p = (D3DVALUE*)((BYTE*)p + dwPositionSize);
this->position.lpvData = (char*)this->position.lpvData + this->position.dwStride;
if (dwFVF & D3DFVF_NORMAL)
{
*p++ = ((D3DVALUE*)this->normal.lpvData)[0];
*p++ = ((D3DVALUE*)this->normal.lpvData)[1];
*p++ = ((D3DVALUE*)this->normal.lpvData)[2];
this->normal.lpvData = (char*)this->normal.lpvData + this->normal.dwStride;
}
if (dwFVF & D3DFVF_RESERVED1)
{
*p++ = 0;
}
if (dwFVF & D3DFVF_DIFFUSE)
{
*p++ = *(D3DVALUE*)this->diffuse.lpvData;
this->diffuse.lpvData = (char*)this->diffuse.lpvData + this->diffuse.dwStride;
}
if (dwFVF & D3DFVF_SPECULAR)
{
*p++ = *(D3DVALUE*)this->specular.lpvData;
this->specular.lpvData = (char*)this->specular.lpvData + this->specular.dwStride;
}
for (DWORD i=0; i < this->nTexCoord; i++)
{
DWORD dwSize = dwTexCoordSizeDummy[i];
memcpy(p, this->textures[i].lpvData, dwSize);
this->textures[i].lpvData = (char*)this->textures[i].lpvData + this->textures[i].dwStride;
p = (D3DVALUE*)((char*)p + dwSize);
}
}
}
else
{
// Pass vertices directly from the user memory
this->dwOutputSize = this->position.dwStride;
this->lpvOut = this->position.lpvData;
this->dwVertexPoolSize = this->dwNumVertices * this->dwOutputSize;
ret = this->StartPrimUserMem(this->position.lpvData);
if (ret != D3D_OK)
return ret;
}
if (op == __PROCPRIMOP_INDEXEDPRIM)
{
ret = this->DrawIndexPrim();
}
else
{ // Non indexed primitive
ret = this->DrawPrim();
}
if (ret != D3D_OK)
return ret;
return this->EndPrim();
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceTL::UpdateDrvViewInfo"
void CDirect3DDeviceTL::UpdateDrvViewInfo(LPD3DVIEWPORT7 lpVwpData)
{
// Update viewport size
CDirect3DDeviceIDP2::UpdateDrvViewInfo(lpVwpData);
// Update Z range
LPD3DHAL_DP2ZRANGE pData;
pData = (LPD3DHAL_DP2ZRANGE)GetHalBufferPointer(D3DDP2OP_ZRANGE, sizeof(*pData));
pData->dvMinZ = lpVwpData->dvMinZ;
pData->dvMaxZ = lpVwpData->dvMaxZ;
}
//---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CDirect3DDeviceTL::SetupFVFData"
HRESULT CDirect3DDeviceTL::SetupFVFData(DWORD *pdwInpVertexSize)
{
this->dwFEFlags &= ~D3DFE_FVF_DIRTY;
this->nTexCoord = FVF_TEXCOORD_NUMBER(this->dwVIDIn);
DWORD dwSize = GetVertexSizeFVF(this->dwVIDIn);
// Add size of texture coordinates
DWORD dwTextureFormats = this->dwVIDIn >> 16;
for (DWORD i=this->nTexCoord; i; i--)
{
dwSize += g_TextureSize[dwTextureFormats & 0x3];
dwTextureFormats >>= 2;
}
if (pdwInpVertexSize)
*pdwInpVertexSize = dwSize;
// In case if COLORVERTEX is TRUE, the vertexAlpha could be overriden
// by vertex alpha
this->lighting.alpha = (DWORD)this->lighting.materialAlpha;
this->lighting.alphaSpecular = (DWORD)this->lighting.materialAlphaS;
return D3D_OK;
}