|
|
#include "pch.cpp"
#pragma hdrstop
/*==========================================================================;
* * Copyright (C) 2000 Microsoft Corporation. All Rights Reserved. * * File: ddi.cpp * Content: Direct3D DDI encapsulation implementations * ***************************************************************************/ #include "d3d8p.h"
#include "ddi.h"
#include "ddrawint.h"
#include "fe.h"
#include "pvvid.h"
#include "ddi.inl"
#ifndef WIN95
extern BOOL bVBSwapEnabled, bVBSwapWorkaround; #endif // WIN95
extern HRESULT ProcessClippedPointSprites(D3DFE_PROCESSVERTICES *pv); extern DWORD D3DFE_GenClipFlags(D3DFE_PROCESSVERTICES *pv); extern DWORD g_DebugFlags; HRESULT ValidateCommandBuffer(LPBYTE pBuffer, DWORD dwCommandLength, DWORD dwStride);
/////////////////////////////////////////////////////////////////////////////
// //
// CD3DDDI //
// //
/////////////////////////////////////////////////////////////////////////////
CD3DDDI::CD3DDDI() { m_StartIndex = 0; m_MinVertexIndex = 0; m_NumVertices = 0; m_BaseVertexIndex = 0; }
//---------------------------------------------------------------------------
CD3DDDI::~CD3DDDI() { return; } /////////////////////////////////////////////////////////////////////////////
// //
// CD3DDDIDX6 //
// //
/////////////////////////////////////////////////////////////////////////////
// Command buffer size tuned to 16K to minimize flushes in Unreal
// * 1 = 16K bytes
const DWORD CD3DDDIDX6::dwD3DDefaultCommandBatchSize = 16384;
CD3DDDIDX6::CD3DDDIDX6() : CD3DDDI() { m_ddiType = D3DDDITYPE_DX6; m_pDevice = NULL; m_bWithinPrimitive = FALSE; m_dwhContext = 0; m_pfnProcessPrimitive = NULL; m_pfnProcessIndexedPrimitive = NULL; m_dwInterfaceNumber = 3;
lpDP2CurrBatchVBI = NULL; TLVbuf_size = 0; TLVbuf_base = 0; dwDP2CommandBufSize = 0; dwDP2CommandLength = 0; lpvDP2Commands = NULL; lpDP2CurrCommand = NULL; wDP2CurrCmdCnt = 0; bDP2CurrCmdOP = 0; bDummy = 0; memset(&dp2data, 0x00, sizeof(dp2data) ) ; dwDP2VertexCount = 0; dwVertexBase = 0; lpDDSCB1 = NULL; allocatedBuf = NULL; alignedBuf = NULL; dwTLVbufChanges = 0; dwDP2Flags = 0; m_pPointStream = NULL; // For the legacy DDI, we say we are DX7
m_dwInterfaceNumber = 3; lpwDPBuffer = NULL; dwDPBufferSize = 0; m_pNullVB = 0; #if DBG
m_bValidateCommands = FALSE; #endif
} //---------------------------------------------------------------------
CD3DDDIDX6::~CD3DDDIDX6() { delete m_pPointStream; m_pPointStream = NULL; if (m_pNullVB) m_pNullVB->DecrementUseCount(); if (allocatedBuf) allocatedBuf->DecrementUseCount(); allocatedBuf = NULL; if (lpDP2CurrBatchVBI) lpDP2CurrBatchVBI->DecrementUseCount(); lpDP2CurrBatchVBI = NULL; if (lpDDSCB1) lpDDSCB1->DecrementUseCount(); lpDDSCB1 = NULL; DestroyContext(); } //---------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::NotSupported"
void CD3DDDIDX6::NotSupported(char* msg) { D3D_ERR("%s is not supported by the current DDI", msg); throw D3DERR_INVALIDCALL; } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::SceneCapture"
void CD3DDDIDX6::SceneCapture(BOOL bState) { D3D8_SCENECAPTUREDATA data;
if (m_pDevice->GetHalCallbacks()->SceneCapture == 0) return;
D3D_INFO(6, "SceneCapture, setting %d dwhContext = %d", bState, m_dwhContext);
memset(&data, 0, sizeof(D3DHAL_SCENECAPTUREDATA)); data.dwhContext = m_dwhContext; data.dwFlag = bState ? D3DHAL_SCENE_CAPTURE_START : D3DHAL_SCENE_CAPTURE_END;
HRESULT ret = m_pDevice->GetHalCallbacks()->SceneCapture(&data);
if (ret != DDHAL_DRIVER_HANDLED || data.ddrval != DD_OK) { D3D_ERR("Driver failed to handle SceneCapture"); throw (data.ddrval); } } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::ClearBatch"
void CD3DDDIDX6::ClearBatch(BOOL bWithinPrimitive) { // Reset command buffer
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)lpvDP2Commands; dwDP2CommandLength = 0; dp2data.dwCommandOffset = 0; dp2data.dwCommandLength = 0; bDP2CurrCmdOP = 0; // Reset vertex buffer
if (!bWithinPrimitive) { dp2data.dwVertexOffset = 0; this->dwDP2VertexCount = 0; this->dwVertexBase = 0; TLVbuf_Base() = 0; if (dp2data.dwFlags & D3DHALDP2_USERMEMVERTICES) { // We are flushing a user mem primitive.
// We need to clear dp2data.lpUMVertices
// since we are done with it. We replace
// it with TLVbuf.
DDASSERT(lpDP2CurrBatchVBI == NULL); dp2data.hDDVertex = TLVbuf_GetVBI()->DriverAccessibleKernelHandle(); lpDP2CurrBatchVBI = TLVbuf_GetVBI(); lpDP2CurrBatchVBI->IncrementUseCount(); dp2data.dwFlags &= ~D3DHALDP2_USERMEMVERTICES; } } } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::Init"
void CD3DDDIDX6::Init( LPD3DBASE pDevice ) { m_pDevice = pDevice; CreateContext(); GrowCommandBuffer(dwD3DDefaultCommandBatchSize); // Fill the dp2data structure with initial values
dp2data.dwFlags = D3DHALDP2_SWAPCOMMANDBUFFER; dp2data.dwVertexType = D3DFVF_TLVERTEX; // Initial assumption
dp2data.dwVertexSize = sizeof(D3DTLVERTEX); // Initial assumption
ClearBatch(FALSE);
// Since we plan to call TLV_Grow for the first time with "TRUE"
dwDP2Flags |= D3DDDI_TLVBUFWRITEONLY; GrowTLVbuf((__INIT_VERTEX_NUMBER*2)*sizeof(D3DTLVERTEX), TRUE);
// Create a dummy sysmem VB to be used as a backup for lowmem situations
LPDIRECT3DVERTEXBUFFER8 t; HRESULT ret = CVertexBuffer::Create(pDevice, sizeof(D3DTLVERTEX), D3DUSAGE_INTERNALBUFFER | D3DUSAGE_DYNAMIC, D3DFVF_TLVERTEX, D3DPOOL_SYSTEMMEM, REF_INTERNAL, &t); if (ret != D3D_OK) { D3D_THROW(ret, "Cannot allocate internal backup TLVBuf"); } m_pNullVB = static_cast<CVertexBuffer*>(t);
m_pPointStream = new CTLStream(FALSE); if (m_pPointStream == NULL) D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal data structure CTLStream");
m_pStream0 = NULL; m_CurrentVertexShader = 0; #if DBG
m_VertexSizeFromShader = 0; #endif
m_pIStream = NULL; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::CreateContext"
void CD3DDDIDX6::CreateContext() { D3D8_CONTEXTCREATEDATA data; HRESULT ret;
D3D_INFO(6, "in CreateContext. Creating Context for driver = %08lx", this);
memset(&data, 0, sizeof(data));
data.hDD = m_pDevice->GetHandle(); data.hSurface = m_pDevice->RenderTarget()->KernelHandle(); if(m_pDevice->ZBuffer() != 0) data.hDDSZ = m_pDevice->ZBuffer()->KernelHandle(); // Hack Alert!! dwhContext is used to inform the driver which version
// of the D3D interface is calling it.
data.dwhContext = m_dwInterfaceNumber; data.dwPID = GetCurrentProcessId(); // Hack Alert!! ddrval is used to inform the driver which driver type
// the runtime thinks it is (DriverStyle registry setting)
data.ddrval = m_ddiType;
data.cjBuffer = dwDPBufferSize; data.pvBuffer = NULL;
ret = m_pDevice->GetHalCallbacks()->CreateContext(&data); if (ret != DDHAL_DRIVER_HANDLED || data.ddrval != DD_OK) { D3D_ERR( "Driver did not handle ContextCreate" ); throw D3DERR_INVALIDCALL; } m_dwhContext = data.dwhContext;
#if 0 //def WIN95
LPWORD lpwDPBufferAlloced = NULL; if (D3DMalloc((void**)&lpwDPBufferAlloced, dwDPBufferSize) != DD_OK) { D3D_ERR( "Out of memory in DeviceCreate" ); throw E_OUTOFMEMORY; } lpwDPBuffer = (LPWORD)(((DWORD) lpwDPBufferAlloced+31) & (~31));
#else
if( dwDPBufferSize && (data.cjBuffer < dwDPBufferSize) ) { D3D_ERR( "Driver did not correctly allocate DrawPrim buffer"); throw D3DERR_INVALIDCALL; }
// Need to save the buffer space provided and its size
dwDPBufferSize = data.cjBuffer; lpwDPBuffer = (LPWORD)data.pvBuffer; #endif
D3D_INFO(6, "in CreateContext. Succeeded. dwhContext = %d", data.dwhContext);
}
//-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::DestroyContext"
void CD3DDDIDX6::DestroyContext() { D3D8_CONTEXTDESTROYDATA data; HRESULT ret;
D3D_INFO(6, "Destroying Context for driver = %08lx", this); D3D_INFO(6, "dwhContext = %d", m_dwhContext);
if( m_dwhContext ) { memset(&data, 0, sizeof(D3DHAL_CONTEXTDESTROYDATA)); data.dwhContext = m_dwhContext; ret = m_pDevice->GetHalCallbacks()->ContextDestroy(&data); if (ret != DDHAL_DRIVER_HANDLED || data.ddrval != DD_OK) { D3D_WARN(0,"Failed ContextDestroy HAL call"); return; } } } //-----------------------------------------------------------------------------
// This code may be needed when we debug some problems
#if 0
void PrintBuffer(LPBYTE alignedBuf, D3D8_DRAWPRIMITIVES2DATA* dp2data, LPBYTE lpvDP2Commands) { FILE* f = fopen("\\ddi.log", "a+"); if (f == NULL) return; fprintf(f, "-----------\n"); fprintf(f, "dwFlags: %d, dwVertexType: 0x%xh, CommandOffset: %d, CommandLength: %d, VertexOffset: %d, VertexLength: %d\n", dp2data->dwFlags, dp2data->dwVertexType, dp2data->dwCommandOffset, dp2data->dwCommandLength, dp2data->dwVertexOffset, dp2data->dwVertexLength, dp2data->dwVertexSize); float* p = (float*)alignedBuf; UINT nTex = FVF_TEXCOORD_NUMBER(dp2data->dwVertexType); for (UINT i=0; i < dp2data->dwVertexLength; i++) { fprintf(f, "%4d %10.5f %10.5f %10.5f %10.5f ", i, p[0], p[1], p[2], p[3]); UINT index = 4; if (dp2data->dwVertexType & D3DFVF_DIFFUSE) { // fprintf(f, "0x%6x ", *(DWORD*)&p[index]);
index++; } if (dp2data->dwVertexType & D3DFVF_SPECULAR) { // fprintf(f, "0x%6x ", *(DWORD*)&p[index]);
index++; } for (UINT j=0; j < nTex; j++) { fprintf(f, "%10.5f %10.5f ", p[index], p[index+1]); index += 2; } fprintf(f, "\n"); p = (float*)((BYTE*)p + dp2data->dwVertexSize); } fclose(f); } #endif // 0
//-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::FlushStates"
void CD3DDDIDX6::FlushStates(BOOL bReturnDriverError, BOOL bWithinPrimitive) { HRESULT dwRet=D3D_OK; if (m_bWithinPrimitive) bWithinPrimitive = TRUE; if (dwDP2CommandLength) // Do we have some instructions to flush ?
{ m_pDevice->IncrementBatchCount();
if (lpDP2CurrBatchVBI) lpDP2CurrBatchVBI->Batch(); // Check if render target and / or z buffer is lost
// Save since it will get overwritten by ddrval after DDI call
DWORD dwVertexSize = dp2data.dwVertexSize;
dp2data.dwVertexLength = dwDP2VertexCount; dp2data.dwCommandLength = dwDP2CommandLength; //we clear this to break re-entering as SW rasterizer needs to lock DDRAWSURFACE
dwDP2CommandLength = 0; // Try and set these 2 values only once during initialization
dp2data.dwhContext = m_dwhContext; dp2data.lpdwRStates = (LPDWORD)lpwDPBuffer; DDASSERT(dp2data.dwVertexSize != 0); D3D_INFO(6, "FVF passed to the driver via DrawPrimitives2 = 0x%08x", dp2data.dwVertexType);
// If we need the same TLVbuf next time do not swap buffers.
// Save and restore this bit
BOOL bSwapVB = (dp2data.dwFlags & D3DHALDP2_SWAPVERTEXBUFFER) != 0; #ifndef WIN95
BOOL bDidWorkAround = FALSE; #endif // WIN95
if (bWithinPrimitive) { dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER; } // At the end of the DP2 call we expect the VB to be unlocked if
// 1. We cannot allow the driver to swap the VB
// 2. We are using a VB (not USERMEMVERTICES)
// 3. It is not TLVbuf
// In this case we might as well tell the driver that it is unlocked.
// More importantly, we need to let DDraw know that the VB is unlocked.
if (!(dp2data.dwFlags & D3DHALDP2_SWAPVERTEXBUFFER)) { if ((lpDP2CurrBatchVBI) && (lpDP2CurrBatchVBI != TLVbuf_GetVBI())) { // This seems contradictory, but IsLocked() checks whether
// the app is holding a Lock.
if(!lpDP2CurrBatchVBI->IsLocked()) { lpDP2CurrBatchVBI->UnlockI(); } } } #ifndef WIN95
else if (bVBSwapWorkaround && lpDP2CurrBatchVBI != 0 && lpDP2CurrBatchVBI == TLVbuf_GetVBI() && lpDP2CurrBatchVBI->GetBufferDesc()->Pool == D3DPOOL_DEFAULT) { static_cast<CDriverVertexBuffer*>(lpDP2CurrBatchVBI)->UnlockI(); bDidWorkAround = TRUE; } if (!bVBSwapEnabled) // Note: bVBSwapEnabled not the same as bSwapVB above.
// bVBSwapEnabled is a global to indicate whether VB
// VB swapping should be turned off due to broken
// Win2K kernel implementation
{ dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER; } #endif // WIN95
// Spin waiting on the driver if wait requested
do { // Need to set this since the driver may have overwrote it by
// setting ddrval = DDERR_WASSTILLDRAWING
dp2data.dwVertexSize = dwVertexSize; dwRet = m_pDevice->GetHalCallbacks()->DrawPrimitives2(&dp2data); if (dwRet != DDHAL_DRIVER_HANDLED) { D3D_ERR ( "Driver not handled in DrawPrimitives2" ); // Need sensible return value in this case,
// currently we return whatever the driver stuck in here.
}
} while (dp2data.ddrval == DDERR_WASSTILLDRAWING);
dwRet = dp2data.ddrval; // update command buffer pointer
if ((dwRet == D3D_OK) && (dp2data.dwFlags & D3DHALDP2_SWAPCOMMANDBUFFER)) { // Implement VidMem command buffer and
// command buffer swapping.
} // update vertex buffer pointer
if ((dwRet == D3D_OK) && (dp2data.dwFlags & D3DHALDP2_SWAPVERTEXBUFFER) && dp2data.lpVertices) { #if DBG
if (this->lpDP2CurrBatchVBI->GetBufferDesc()->Pool == D3DPOOL_DEFAULT) { if ((VOID*)static_cast<CDriverVertexBuffer*>(this->lpDP2CurrBatchVBI)->GetCachedDataPointer() != (VOID*)dp2data.fpVidMem_VB) { DPF(2, "Driver swapped VB pointer in FlushStates"); } } #endif // DBG
if (lpDP2CurrBatchVBI == TLVbuf_GetVBI()) { this->alignedBuf = (LPVOID)dp2data.fpVidMem_VB; this->TLVbuf_size = dp2data.dwLinearSize_VB; }
this->lpDP2CurrBatchVBI->SetCachedDataPointer( (BYTE*)dp2data.fpVidMem_VB); } #ifndef WIN95
if (bDidWorkAround) { CDriverVertexBuffer *pVB = static_cast<CDriverVertexBuffer*>(lpDP2CurrBatchVBI);
// Prepare a LockData structure for the HAL call
D3D8_LOCKDATA lockData; ZeroMemory(&lockData, sizeof lockData);
lockData.hDD = m_pDevice->GetHandle(); lockData.hSurface = pVB->BaseKernelHandle(); lockData.bHasRange = FALSE; lockData.dwFlags = D3DLOCK_DISCARD | D3DLOCK_NOSYSLOCK;
HRESULT hr = m_pDevice->GetHalCallbacks()->Lock(&lockData); if (FAILED(hr)) { D3D_ERR("Driver failed Lock in FlushStates"); if (SUCCEEDED(dwRet)) { dwRet = hr; } this->alignedBuf = 0; } else { #if DBG
if (this->alignedBuf != lockData.lpSurfData) { DPF(2, "Driver swapped VB pointer at Lock in FlushStates"); } #endif // DBG
pVB->SetCachedDataPointer((BYTE*)lockData.lpSurfData); this->alignedBuf = lockData.lpSurfData; } } #endif // WIN95
// Restore flag if necessary
if (bSwapVB) dp2data.dwFlags |= D3DHALDP2_SWAPVERTEXBUFFER; // Restore to value before the DDI call
dp2data.dwVertexSize = dwVertexSize; ClearBatch(bWithinPrimitive); } // There are situations when the command stream has no data,
// but there is data in the vertex pool. This could happen, for instance
// if every triangle got rejected while clipping. In this case we still
// need to "Flush out" the vertex data.
else if (dp2data.dwCommandLength == 0) { ClearBatch(bWithinPrimitive); }
if( FAILED( dwRet ) ) { ClearBatch(FALSE); if( !bReturnDriverError ) { switch( dwRet ) { case D3DERR_OUTOFVIDEOMEMORY: D3D_ERR("Driver out of video memory!"); break; case D3DERR_COMMAND_UNPARSED: D3D_ERR("Driver could not parse this batch!"); break; default: D3D_ERR("Driver returned error: %s", HrToStr(dwRet)); break; } DPF_ERR("Driver failed command batch. Attempting to reset device" " state. The device may now be in an unstable state and" " the application may experience an access violation."); } else { throw dwRet; } } } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::FlushstatesReq"
void CD3DDDIDX6::FlushStatesReq(DWORD dwReqSize) { DWORD sav = (dp2data.dwFlags & D3DHALDP2_SWAPVERTEXBUFFER); dp2data.dwReqVertexBufSize = dwReqSize; dp2data.dwFlags |= D3DHALDP2_SWAPVERTEXBUFFER | D3DHALDP2_REQVERTEXBUFSIZE; try { FlushStates(); } catch( HRESULT hr ) { dp2data.dwFlags &= ~(D3DHALDP2_SWAPVERTEXBUFFER | D3DHALDP2_REQVERTEXBUFSIZE); dp2data.dwFlags |= sav; throw hr; }
dp2data.dwFlags &= ~(D3DHALDP2_SWAPVERTEXBUFFER | D3DHALDP2_REQVERTEXBUFSIZE); dp2data.dwFlags |= sav; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::FlushStatesCmdBufReq"
void CD3DDDIDX6::FlushStatesCmdBufReq(DWORD dwReqSize) { dp2data.dwReqCommandBufSize = dwReqSize; dp2data.dwFlags |= D3DHALDP2_REQCOMMANDBUFSIZE; try { FlushStates(); } catch( HRESULT hr ) { dp2data.dwFlags &= ~D3DHALDP2_REQCOMMANDBUFSIZE; throw hr; } dp2data.dwFlags &= ~D3DHALDP2_REQCOMMANDBUFSIZE; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::ValidateDevice"
void CD3DDDIDX6::ValidateDevice(LPDWORD lpdwNumPasses) { HRESULT ret; D3D8_VALIDATETEXTURESTAGESTATEDATA vd; memset( &vd, 0, sizeof( vd ) ); vd.dwhContext = m_dwhContext;
// First, Update textures since drivers pass /fail this call based
// on the current texture handles
m_pDevice->UpdateTextures();
// Flush states, so we can validate the current state
FlushStates();
// Now ask the driver!
ret = m_pDevice->GetHalCallbacks()->ValidateTextureStageState(&vd); *lpdwNumPasses = vd.dwNumPasses;
if (ret != DDHAL_DRIVER_HANDLED) throw E_NOTIMPL; else if (FAILED(vd.ddrval)) throw vd.ddrval; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::ReserveSpaceInCommandBuffer"
LPVOID CD3DDDIDX6::ReserveSpaceInCommandBuffer(UINT ByteCount) { if (dwDP2CommandLength + ByteCount > dwDP2CommandBufSize) { // Request the driver to grow the command buffer upon flush
FlushStatesCmdBufReq(ByteCount); // Check if the driver did give us what we need or do it ourselves
GrowCommandBuffer(ByteCount); } return (BYTE*)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::SetRenderTarget"
void CD3DDDIDX6::SetRenderTarget(CBaseSurface *pTarget, CBaseSurface *pZ) { HRESULT ret;
// We are going to destroy all texture handles, so we need to unset
// all currently bound textures, because we have seen DX6 drivers
// crash when called to destroy a texture handle of a currently set
// texture - snene (4/24/00)
m_pDevice->m_dwStageDirty = (1ul << m_pDevice->m_dwMaxTextureBlendStages) - 1ul; // set dirty so that UpdateTextures() is called next time around
m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_TEXTURE_UPDATE; for (DWORD dwStage = 0; dwStage < m_pDevice->m_dwMaxTextureBlendStages; dwStage++) { SetTSS(dwStage, (D3DTEXTURESTAGESTATETYPE)D3DTSS_TEXTUREMAP, 0); m_pDevice->m_dwDDITexHandle[dwStage] = 0; }
// Flush before switching RenderTarget..
FlushStates();
D3D8_SETRENDERTARGETDATA rtData; memset( &rtData, 0, sizeof( rtData ) ); rtData.dwhContext = m_dwhContext; rtData.hDDS = pTarget->KernelHandle(); if( pZ ) rtData.hDDSZ = pZ->KernelHandle();
ret = m_pDevice->GetHalCallbacks()->SetRenderTarget( &rtData ); if ((ret != DDHAL_DRIVER_HANDLED) || (rtData.ddrval != DD_OK)) { D3D_ERR( "Driver failed SetRenderTarget call" ); // Need sensible return value in this case,
// currently we return whatever the driver stuck in here.
ret = rtData.ddrval; throw ret; } if( rtData.bNeedUpdate ) { m_pDevice->UpdateDriverStates(); } }
//-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::SetRenderState"
void CD3DDDIDX6::SetRenderState(D3DRENDERSTATETYPE dwStateType, DWORD value) { if (bDP2CurrCmdOP == D3DDP2OP_RENDERSTATE) { // Last instruction is a renderstate, append this one to it
if (dwDP2CommandLength + sizeof(D3DHAL_DP2RENDERSTATE) <= dwDP2CommandBufSize) { LPD3DHAL_DP2RENDERSTATE lpRState = (LPD3DHAL_DP2RENDERSTATE) ((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt; lpRState->RenderState = dwStateType; lpRState->dwState = value; dwDP2CommandLength += sizeof(D3DHAL_DP2RENDERSTATE); #ifndef _IA64_
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
return; } } // Check for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2RENDERSTATE) > dwDP2CommandBufSize) { FlushStates();
// Since we ran out of space, we were not able to put
// (dwStateType, value) into the batch so rstates will reflect only
// the last batched renderstate (since the driver updates rstates
// from the batch). To fix this, we simply put the current
// (dwStateType, value) into rstates.
m_pDevice->UpdateRenderState(dwStateType, value); } // Add new renderstate instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->bCommand = D3DDP2OP_RENDERSTATE; bDP2CurrCmdOP = D3DDP2OP_RENDERSTATE; lpDP2CurrCommand->bReserved = 0; lpDP2CurrCommand->wStateCount = 1; wDP2CurrCmdCnt = 1; #ifndef _IA64_
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
// Add renderstate data
LPD3DHAL_DP2RENDERSTATE lpRState; lpRState = (LPD3DHAL_DP2RENDERSTATE)(lpDP2CurrCommand + 1); lpRState->RenderState = dwStateType; lpRState->dwState = value; dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2RENDERSTATE); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::UpdateWInfo"
void CD3DDDIDX6::UpdateWInfo(CONST D3DMATRIX* lpMat) { LPD3DHAL_DP2WINFO pData; pData = (LPD3DHAL_DP2WINFO) GetHalBufferPointer(D3DDP2OP_WINFO, sizeof(*pData)); D3DMATRIX m = *lpMat; if( (m._33 == m._34) || (m._33 == 0.0f) ) { D3D_WARN(1, "Cannot compute WNear and WFar from the supplied projection matrix"); D3D_WARN(1, "Setting wNear to 0.0 and wFar to 1.0"); pData->dvWNear = 0.0f; pData->dvWFar = 1.0f; return; } pData->dvWNear = m._44 - m._43/m._33*m._34; pData->dvWFar = (m._44 - m._43)/(m._33 - m._34)*m._34 + m._44; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::SetViewport"
void CD3DDDIDX6::SetViewport(CONST D3DVIEWPORT8* lpVwpData) { LPD3DHAL_DP2VIEWPORTINFO pData; pData = (LPD3DHAL_DP2VIEWPORTINFO)GetHalBufferPointer(D3DDP2OP_VIEWPORTINFO, sizeof(*pData)); pData->dwX = lpVwpData->X; pData->dwY = lpVwpData->Y; pData->dwWidth = lpVwpData->Width; pData->dwHeight = lpVwpData->Height; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::SetTSS"
void CD3DDDIDX6::SetTSS(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, DWORD dwValue) { // Filter unsupported states
if (dwState >= m_pDevice->m_tssMax) return;
// Map DX8 filter enums to DX6/7 enums
switch (dwState) { case D3DTSS_MAGFILTER: dwValue = texf2texfg[min(D3DTEXF_GAUSSIANCUBIC,dwValue)]; break; case D3DTSS_MINFILTER: dwValue = texf2texfn[min(D3DTEXF_GAUSSIANCUBIC,dwValue)]; break; case D3DTSS_MIPFILTER: dwValue = texf2texfp[min(D3DTEXF_GAUSSIANCUBIC,dwValue)]; break; }
if (bDP2CurrCmdOP == D3DDP2OP_TEXTURESTAGESTATE) { // Last instruction is a texture stage state, append this one to it
if (dwDP2CommandLength + sizeof(D3DHAL_DP2TEXTURESTAGESTATE) <= dwDP2CommandBufSize) { LPD3DHAL_DP2TEXTURESTAGESTATE lpRState = (LPD3DHAL_DP2TEXTURESTAGESTATE)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt; lpRState->wStage = (WORD)dwStage; lpRState->TSState = (WORD)dwState; lpRState->dwValue = dwValue; dwDP2CommandLength += sizeof(D3DHAL_DP2TEXTURESTAGESTATE); #ifndef _IA64_
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
return; } } // Check for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TEXTURESTAGESTATE) > dwDP2CommandBufSize) { FlushStates(); } // Add new renderstate instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->bCommand = D3DDP2OP_TEXTURESTAGESTATE; bDP2CurrCmdOP = D3DDP2OP_TEXTURESTAGESTATE; lpDP2CurrCommand->bReserved = 0; lpDP2CurrCommand->wStateCount = 1; wDP2CurrCmdCnt = 1; #ifndef _IA64_
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
// Add renderstate data
LPD3DHAL_DP2TEXTURESTAGESTATE lpRState = (LPD3DHAL_DP2TEXTURESTAGESTATE)(lpDP2CurrCommand + 1); lpRState->wStage = (WORD)dwStage; lpRState->TSState = (WORD)dwState; lpRState->dwValue = dwValue; dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TEXTURESTAGESTATE); } //---------------------------------------------------------------------
// Map D3DPRIMITIVETYPE to D3DHAL_DP2OPERATION for indexed primitives
const WORD iprim2cmdop[] = { 0, // Invalid
0, // Points are invalid too
D3DDP2OP_INDEXEDLINELIST2, D3DDP2OP_INDEXEDLINESTRIP, D3DDP2OP_INDEXEDTRIANGLELIST2, D3DDP2OP_INDEXEDTRIANGLESTRIP, D3DDP2OP_INDEXEDTRIANGLEFAN }; // Map D3DPRIMITIVETYPE to D3DHAL_DP2OPERATION
const WORD prim2cmdop[] = { 0, // Invalid
D3DDP2OP_POINTS, D3DDP2OP_LINELIST, D3DDP2OP_LINESTRIP, D3DDP2OP_TRIANGLELIST, D3DDP2OP_TRIANGLESTRIP, D3DDP2OP_TRIANGLEFAN }; // Map D3DPRIMITIVETYPE to bytes needed in command stream
const WORD prim2cmdsz[] = { 0, // Invalid
sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2POINTS), sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2LINELIST), sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2LINESTRIP), sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TRIANGLELIST), sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TRIANGLESTRIP), sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TRIANGLEFAN) }; //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::SetVertexShader"
void CD3DDDIDX6::SetVertexShader(DWORD dwHandle) { DXGASSERT(D3DVSD_ISLEGACY(dwHandle)); DXGASSERT( (dwHandle == 0) || FVF_TRANSFORMED(dwHandle) ); m_CurrentVertexShader = dwHandle; #if DBG
m_VertexSizeFromShader = ComputeVertexSizeFVF(dwHandle); #endif
} //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::SetVertexShaderHW"
void CD3DDDIDX6::SetVertexShaderHW(DWORD dwHandle) { DXGASSERT(D3DVSD_ISLEGACY(dwHandle)); DXGASSERT( (dwHandle == 0) || FVF_TRANSFORMED(dwHandle) ); m_CurrentVertexShader = dwHandle; #if DBG
m_VertexSizeFromShader = ComputeVertexSizeFVF(dwHandle); #endif
} //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::SetStreamSource"
void CD3DDDIDX6::SetStreamSource(UINT StreamIndex, CVStream* pStream) { DXGASSERT(StreamIndex == 0); m_pStream0 = pStream; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::SetIndices"
void CD3DDDIDX6::SetIndices(CVIndexStream* pStream) { m_pIStream = pStream; } //-----------------------------------------------------------------------------
// Assumes that VB has not been changed between DrawPrimitive calss
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6_DrawPrimitiveFast"
void CD3DDDIDX6_DrawPrimitiveFast(CD3DBase* pDevice, D3DPRIMITIVETYPE primType, UINT StartVertex, UINT PrimitiveCount) { CD3DDDIDX6* pDDI = static_cast<CD3DDDIDX6*>(pDevice->m_pDDI);
UINT NumVertices = GETVERTEXCOUNT(primType, PrimitiveCount); pDDI->SetWithinPrimitive(TRUE);
if(pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { pDevice->UpdateTextures(); pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; }
pDDI->dwDP2VertexCount = max(pDDI->dwDP2VertexCount, StartVertex + NumVertices);
// Check for space in the command buffer for new command.
// The vertices are already in the vertex buffer.
if (pDDI->dwDP2CommandLength + prim2cmdsz[primType] > pDDI->dwDP2CommandBufSize) { pDDI->FlushStates(FALSE, TRUE); }
// Insert non indexed primitive instruction
LPD3DHAL_DP2COMMAND lpDP2CurrCommand; lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)pDDI->lpvDP2Commands + pDDI->dwDP2CommandLength + pDDI->dp2data.dwCommandOffset); pDDI->bDP2CurrCmdOP = (BYTE)prim2cmdop[primType]; // This will initialize bCommand and bReserved
*(WORD*)&lpDP2CurrCommand->bCommand = prim2cmdop[primType]; if (pDDI->bDP2CurrCmdOP != D3DDP2OP_POINTS) { // Linestrip, trianglestrip, trianglefan, linelist and trianglelist are identical
pDDI->wDP2CurrCmdCnt = (WORD)PrimitiveCount; lpDP2CurrCommand->wPrimitiveCount = (WORD)PrimitiveCount; LPD3DHAL_DP2LINESTRIP lpStrip = (LPD3DHAL_DP2LINESTRIP)(lpDP2CurrCommand + 1); lpStrip->wVStart = (WORD)StartVertex; } else { pDDI->wDP2CurrCmdCnt = 1; lpDP2CurrCommand->wPrimitiveCount = 1; LPD3DHAL_DP2POINTS lpPoints = (LPD3DHAL_DP2POINTS)(lpDP2CurrCommand + 1); lpPoints->wCount = (WORD)NumVertices; lpPoints->wVStart = (WORD)StartVertex; } pDDI->dwDP2CommandLength += prim2cmdsz[primType];
#if DBG
if (pDDI->m_bValidateCommands) pDDI->ValidateCommand(lpDP2CurrCommand); #endif
pDDI->SetWithinPrimitive(FALSE); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6_DrawPrimitive"
void CD3DDDIDX6_DrawPrimitive(CD3DBase* pDevice, D3DPRIMITIVETYPE primType, UINT StartVertex, UINT PrimitiveCount) { #if DBG
if (!(pDevice->BehaviorFlags() & D3DCREATE_PUREDEVICE)) { CD3DHal* pDev = static_cast<CD3DHal*>(pDevice); UINT nVer = GETVERTEXCOUNT(primType, PrimitiveCount); pDev->ValidateDraw2(primType, StartVertex, PrimitiveCount, nVer, FALSE); } #endif // DBG
CD3DDDIDX6* pDDI = static_cast<CD3DDDIDX6*>(pDevice->m_pDDI); CVStream* pStream0 = &pDevice->m_pStream[0]; D3DFE_PROCESSVERTICES* pv = static_cast<CD3DHal*>(pDevice)->m_pv;
pv->dwNumVertices = GETVERTEXCOUNT(primType, PrimitiveCount); pv->dwVIDOut = pDDI->m_CurrentVertexShader; pv->dwOutputSize = pStream0->m_dwStride; DXGASSERT(pStream0->m_pVB != NULL); #if DBG
if (pStream0->m_dwStride != pDDI->m_VertexSizeFromShader) { D3D_THROW_FAIL("Device requires stream stride and vertex size," "computed from vertex shader, to be the same"); } #endif
if(pStream0->m_pVB->IsD3DManaged()) { BOOL bDirty = FALSE; HRESULT result = pDevice->ResourceManager()->UpdateVideo(pStream0->m_pVB->RMHandle(), &bDirty); if(result != D3D_OK) { D3D_THROW(result, "Resource manager failed to create or update video memory VB"); } }
pDDI->StartPrimVB(pv, pStream0, StartVertex);
CD3DDDIDX6_DrawPrimitiveFast(pDevice, primType, StartVertex, PrimitiveCount); pDevice->m_pfnDrawPrim = CD3DDDIDX6_DrawPrimitiveFast; } //-----------------------------------------------------------------------------
// Assumes that VB has not been changed between DrawIndexedPrimitive calls
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6_IndexedDrawPrimitiveFast"
void CD3DDDIDX6_DrawIndexedPrimitiveFast(CD3DBase* pDevice, D3DPRIMITIVETYPE primType, UINT BaseVertexIndex, UINT MinIndex, UINT NumVertices, UINT StartIndex, UINT PrimitiveCount) { CD3DDDIDX6* pDDI = static_cast<CD3DDDIDX6*>(pDevice->m_pDDI); CVIndexStream* pIStream = pDevice->m_pIndexStream;
UINT NumIndices = GETVERTEXCOUNT(primType, PrimitiveCount); WORD* lpwIndices = (WORD*)(pIStream->Data() + StartIndex * pIStream->m_dwStride); pDDI->SetWithinPrimitive(TRUE);
#if DBG
// DP2 HAL supports 16 bit indices only
if (pIStream->m_dwStride != 2) { D3D_THROW_FAIL("Device does not support 32-bit indices"); } DXGASSERT(BaseVertexIndex <= 0xFFFF && NumVertices <= 0xFFFF && PrimitiveCount <= 0xFFFF); #endif
DWORD dwByteCount; // Command length plus indices
DWORD dwIndicesByteCount; // Indices only
if(pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { pDevice->UpdateTextures(); pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } dwIndicesByteCount = NumIndices << 1; dwByteCount = dwIndicesByteCount + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2STARTVERTEX);
LPD3DHAL_DP2COMMAND lpDP2CurrCommand; lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND) pDDI->ReserveSpaceInCommandBuffer(dwByteCount); pDDI->bDP2CurrCmdOP = (BYTE)iprim2cmdop[primType]; // This will initialize bCommand and bReserved
*(WORD*)&lpDP2CurrCommand->bCommand = iprim2cmdop[primType]; lpDP2CurrCommand->wPrimitiveCount = (WORD)PrimitiveCount;
LPBYTE pIndices = (BYTE*)(lpDP2CurrCommand + 1); // Place for indices
WORD* pStartVertex = &((LPD3DHAL_DP2STARTVERTEX)(lpDP2CurrCommand+1))->wVStart; pIndices += sizeof(D3DHAL_DP2STARTVERTEX);
#if DBG
if (lpDP2CurrCommand->bCommand == 0) { D3D_THROW_FAIL("Illegal primitive type"); } #endif
*pStartVertex = (WORD)BaseVertexIndex; memcpy(pIndices, lpwIndices, dwIndicesByteCount);
pDDI->wDP2CurrCmdCnt = (WORD)PrimitiveCount; pDDI->dwDP2CommandLength += dwByteCount;
#if DBG
if (pDDI->m_bValidateCommands) pDDI->ValidateCommand(lpDP2CurrCommand); #endif
pDDI->dwDP2VertexCount = max(pDDI->dwDP2VertexCount, MinIndex + NumVertices);
// End of the primitive
pDDI->SetWithinPrimitive(FALSE); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6_IndexedDrawPrimitive"
void CD3DDDIDX6_DrawIndexedPrimitive(CD3DBase* pDevice, D3DPRIMITIVETYPE primType, UINT BaseVertexIndex, UINT MinIndex, UINT NumVertices, UINT StartIndex, UINT PrimitiveCount) { #if DBG
if (!(pDevice->BehaviorFlags() & D3DCREATE_PUREDEVICE)) { CD3DHal* pDev = static_cast<CD3DHal*>(pDevice); pDev->ValidateDraw2(primType, MinIndex + BaseVertexIndex, PrimitiveCount, NumVertices, TRUE, StartIndex); } #endif // DBG
D3DFE_PROCESSVERTICES* pv = static_cast<CD3DHal*>(pDevice)->m_pv; CD3DDDIDX6* pDDI = static_cast<CD3DDDIDX6*>(pDevice->m_pDDI); CVIndexStream* pIStream = pDevice->m_pIndexStream; CVStream* pStream0 = &pDevice->m_pStream[0];
DXGASSERT(pStream0->m_pVB != NULL); if(pStream0->m_pVB->IsD3DManaged()) { BOOL bDirty = FALSE; HRESULT result = pDevice->ResourceManager()->UpdateVideo(pStream0->m_pVB->RMHandle(), &bDirty); if(result != D3D_OK) { D3D_THROW(result, "Resource manager failed to create or update video memory VB"); } }
// Parameters needed for StartPrimVB
pv->dwNumVertices = NumVertices + MinIndex; pv->dwVIDOut = pDDI->m_CurrentVertexShader; pv->dwOutputSize = pStream0->m_dwStride; #if DBG
if (pStream0->m_dwStride != pDDI->m_VertexSizeFromShader) { D3D_THROW_FAIL("Device requires stream stride and vertex size," "computed from vertex shader, to be the same"); } #endif
pDDI->StartPrimVB(pv, pStream0, BaseVertexIndex);
CD3DDDIDX6_DrawIndexedPrimitiveFast(pDevice, primType, BaseVertexIndex, MinIndex, NumVertices, StartIndex, PrimitiveCount); pDevice->m_pfnDrawIndexedPrim = CD3DDDIDX6_DrawIndexedPrimitiveFast; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::DrawPrimitiveUP"
void CD3DDDIDX6::DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount) { #if DBG
if (m_pDevice->m_pStream[0].m_dwStride != m_VertexSizeFromShader) { D3D_THROW_FAIL("Device requires stream stride and vertex size," "computed from vertex shader, to be the same"); } #endif
UINT NumVertices = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount); if (NumVertices > LOWVERTICESNUMBER) { this->FlushStates(); if (lpDP2CurrBatchVBI) { lpDP2CurrBatchVBI->DecrementUseCount(); lpDP2CurrBatchVBI = NULL; } this->dwDP2VertexCount = NumVertices; #if DBG
DXGASSERT(PrimitiveCount <= 0xFFFF && this->dwDP2VertexCount <= 0xFFFF); #endif
dp2data.dwVertexType = m_CurrentVertexShader; dp2data.dwVertexSize = m_pDevice->m_pStream[0].m_dwStride; dp2data.lpVertices = m_pDevice->m_pStream[0].m_pData; dp2data.dwFlags |= D3DHALDP2_USERMEMVERTICES; dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER; if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { m_pDevice->UpdateTextures(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } // Insert non indexed primitive instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); bDP2CurrCmdOP = (BYTE)prim2cmdop[PrimitiveType]; lpDP2CurrCommand->bCommand = bDP2CurrCmdOP; lpDP2CurrCommand->bReserved = 0; if (bDP2CurrCmdOP == D3DDP2OP_POINTS) { wDP2CurrCmdCnt = 1; LPD3DHAL_DP2POINTS lpPoints = (LPD3DHAL_DP2POINTS)(lpDP2CurrCommand + 1); lpPoints->wCount = (WORD)this->dwDP2VertexCount; lpPoints->wVStart = 0; } else { // Linestrip, trianglestrip, trianglefan, linelist and trianglelist are identical
wDP2CurrCmdCnt = (WORD)PrimitiveCount; LPD3DHAL_DP2LINESTRIP lpStrip = (LPD3DHAL_DP2LINESTRIP)(lpDP2CurrCommand + 1); lpStrip->wVStart = 0; } lpDP2CurrCommand->wPrimitiveCount = wDP2CurrCmdCnt; dwDP2CommandLength += prim2cmdsz[PrimitiveType];
this->FlushStates(); dp2data.dwFlags &= ~D3DHALDP2_USERMEMVERTICES; } else { // There is no PURE HAL device for pre-DX8 HALs, so this cast is safe
CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice); D3DFE_PROCESSVERTICES& pv = *pDevice->m_pv; // Copy vertices to the internal TL buffer and insert a new
// DrawPrimitive command
UINT VertexPoolSize = m_pDevice->m_pStream[0].m_dwStride * NumVertices; pv.dwNumVertices = NumVertices; pv.dwOutputSize = m_pDevice->m_pStream[0].m_dwStride; pv.primType = PrimitiveType; pv.dwNumPrimitives = PrimitiveCount; pv.dwVIDOut = m_CurrentVertexShader; pv.lpvOut = StartPrimTL(&pv, VertexPoolSize, TRUE); memcpy(pv.lpvOut, m_pDevice->m_pStream[0].m_pData, VertexPoolSize); DrawPrim(&pv); EndPrim(pv.dwOutputSize); } } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::DrawIndexedPrimitiveUP"
void CD3DDDIDX6::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertexIndices, UINT PrimitiveCount) { #if DBG
if (m_pDevice->m_pStream[0].m_dwStride != m_VertexSizeFromShader) { D3D_THROW_FAIL("Device requires stream stride and vertex size," "computed from vertex shader, to be the same"); } #endif
if (NumVertexIndices > LOWVERTICESNUMBER) { this->FlushStates(); if (lpDP2CurrBatchVBI) { lpDP2CurrBatchVBI->DecrementUseCount(); lpDP2CurrBatchVBI = NULL; } this->dwDP2VertexCount = NumVertexIndices + MinVertexIndex; #if DBG
DXGASSERT(PrimitiveCount <= 0xFFFF && this->dwDP2VertexCount <= 0xFFFF); #endif
dp2data.dwVertexType = m_CurrentVertexShader; dp2data.dwVertexSize = m_pDevice->m_pStream[0].m_dwStride; dp2data.lpVertices = m_pDevice->m_pStream[0].m_pData; dp2data.dwFlags |= D3DHALDP2_USERMEMVERTICES; dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER; DWORD dwByteCount; // Command length plus indices
DWORD dwIndicesByteCount; // Indices only
if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { m_pDevice->UpdateTextures(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } dwIndicesByteCount = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount) << 1; dwByteCount = dwIndicesByteCount + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2STARTVERTEX);
if (dwDP2CommandLength + dwByteCount > dwDP2CommandBufSize) { // Request the driver to grow the command buffer upon flush
dp2data.dwReqCommandBufSize = dwByteCount; dp2data.dwFlags |= D3DHALDP2_REQCOMMANDBUFSIZE; try { FlushStates(FALSE,TRUE); dp2data.dwFlags &= ~D3DHALDP2_REQCOMMANDBUFSIZE; } catch (HRESULT ret) { dp2data.dwFlags &= ~D3DHALDP2_REQCOMMANDBUFSIZE; throw ret; } // Check if the driver did give us what we need or do it ourselves
GrowCommandBuffer(dwByteCount); } // Insert indexed primitive instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->bReserved = 0; lpDP2CurrCommand->wPrimitiveCount = (WORD)PrimitiveCount;
LPBYTE pIndices = (BYTE*)(lpDP2CurrCommand + 1); // Place for indices
lpDP2CurrCommand->bCommand = (BYTE)iprim2cmdop[PrimitiveType]; WORD* pStartVertex = &((LPD3DHAL_DP2STARTVERTEX)(lpDP2CurrCommand+1))->wVStart; pIndices += sizeof(D3DHAL_DP2STARTVERTEX); *pStartVertex = 0;
bDP2CurrCmdOP = lpDP2CurrCommand->bCommand;
memcpy(pIndices, m_pDevice->m_pIndexStream->m_pData, dwIndicesByteCount);
wDP2CurrCmdCnt = lpDP2CurrCommand->wPrimitiveCount; dwDP2CommandLength += dwByteCount;
this->FlushStates(); dp2data.dwFlags &= ~D3DHALDP2_USERMEMVERTICES; } else { // There is no PURE HAL device for pre-DX8 HALs, so this cast is safe
CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice); D3DFE_PROCESSVERTICES& pv = *pDevice->m_pv;
m_MinVertexIndex = MinVertexIndex; // Copy vertices to the internal TL buffer and insert a new
// DrawIndexedPrimitive command
UINT VertexPoolSize = m_pDevice->m_pStream[0].m_dwStride * NumVertexIndices; pv.dwNumVertices = NumVertexIndices; pv.dwOutputSize = m_pDevice->m_pStream[0].m_dwStride; pv.primType = PrimitiveType; pv.dwNumPrimitives = PrimitiveCount; pv.dwVIDOut = m_CurrentVertexShader;
// Copy vertices
UINT FirstVertexOffset = MinVertexIndex * pv.dwOutputSize; pv.lpvOut = StartPrimTL(&pv, VertexPoolSize, TRUE); memcpy(pv.lpvOut, m_pDevice->m_pStream[0].m_pData + FirstVertexOffset, VertexPoolSize);
pv.dwNumIndices = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount); pv.dwIndexSize = m_pDevice->m_pIndexStream->m_dwStride; pv.lpwIndices = (WORD*)(m_pDevice->m_pIndexStream->Data());
m_dwIndexOffset = MinVertexIndex; AddVertices(pv.dwNumVertices);
DrawIndexPrim(&pv);
MovePrimitiveBase(NumVertexIndices); EndPrim(pv.dwOutputSize); } } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::DrawPrimPS"
void CD3DDDIDX6::DrawPrimPS(D3DFE_PROCESSVERTICES* pv) { CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice); BYTE* p = (BYTE*)pv->lpvOut; float PointSize = *(float*)&pv->lpdwRStates[D3DRS_POINTSIZE]; float PointSizeMin = *(float*)&pv->lpdwRStates[D3DRS_POINTSIZE_MIN]; if (PointSize < PointSizeMin) PointSize = PointSizeMin; if (PointSize > pv->PointSizeMax) PointSize = pv->PointSizeMax;
for (UINT i=0; i < pv->dwNumVertices; i++) { if (pv->dwVIDOut & D3DFVF_PSIZE) { PointSize = *(float*)(p + pv->pointSizeOffsetOut); if (PointSize < PointSizeMin) PointSize = PointSizeMin; if (PointSize > pv->PointSizeMax) PointSize = pv->PointSizeMax; } DWORD diffuse = 0; DWORD specular = 0; if (pv->dwVIDOut & D3DFVF_DIFFUSE) diffuse = *(DWORD*)(p + pv->diffuseOffsetOut); if (pv->dwVIDOut & D3DFVF_SPECULAR) specular = *(DWORD*)(p + pv->specularOffsetOut); NextSprite(((float*)p)[0], ((float*)p)[1], // x, y
((float*)p)[2], ((float*)p)[3], // z, w
diffuse, specular, (float*)(p + pv->texOffsetOut), pv->dwTextureCoordSizeTotal, PointSize); p += pv->dwOutputSize; } } //---------------------------------------------------------------------
// Uses the following members of D3DFE_PROCESSVERTICES:
// primType
// dwNumVertices
// dwNumPrimitives
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::DrawPrim"
void CD3DDDIDX6::DrawPrim(D3DFE_PROCESSVERTICES* pv) { #ifdef DEBUG_PIPELINE
if (g_DebugFlags & __DEBUG_NORENDERING) return; #endif
D3DPRIMITIVETYPE primType = pv->primType; if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { m_pDevice->UpdateTextures(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } if (pv->primType == D3DPT_POINTLIST && pv->dwDeviceFlags & D3DDEV_DOPOINTSPRITEEMULATION) { DrawPrimPS(pv); return; } // Check for space in the command buffer for new command.
// The vertices are already in the vertex buffer.
if (dwDP2CommandLength + prim2cmdsz[primType] > dwDP2CommandBufSize) { FlushStates(FALSE,TRUE); } this->AddVertices(pv->dwNumVertices); // Insert non indexed primitive instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); bDP2CurrCmdOP = (BYTE)prim2cmdop[primType]; lpDP2CurrCommand->bCommand = bDP2CurrCmdOP; lpDP2CurrCommand->bReserved = 0; if (bDP2CurrCmdOP == D3DDP2OP_POINTS) { wDP2CurrCmdCnt = 1; LPD3DHAL_DP2POINTS lpPoints = (LPD3DHAL_DP2POINTS)(lpDP2CurrCommand + 1); lpPoints->wCount = (WORD)pv->dwNumVertices; lpPoints->wVStart = (WORD)this->dwVertexBase; } else { // Linestrip, trianglestrip, trianglefan, linelist and trianglelist are identical
wDP2CurrCmdCnt = (WORD)pv->dwNumPrimitives; LPD3DHAL_DP2LINESTRIP lpStrip = (LPD3DHAL_DP2LINESTRIP)(lpDP2CurrCommand + 1); lpStrip->wVStart = (WORD)this->dwVertexBase; } lpDP2CurrCommand->wPrimitiveCount = wDP2CurrCmdCnt; dwDP2CommandLength += prim2cmdsz[primType];
this->MovePrimitiveBase(pv->dwNumVertices); #if DBG
if (m_bValidateCommands) ValidateCommand(lpDP2CurrCommand); #endif
} //---------------------------------------------------------------------
//
// The vertices are already in the vertex buffer.
//
// Uses the following members of D3DFE_PROCESSVERTICES:
// primType
// dwNumVertices
// dwNumPrimitives
// dwNumIndices
// dwIndexOffset
// dwIndexSize
// lpwIndices
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDDIDX6::DrawIndexPrim"
void CD3DDDIDX6::DrawIndexPrim(D3DFE_PROCESSVERTICES* pv) { #ifdef DEBUG_PIPELINE
if (g_DebugFlags & __DEBUG_NORENDERING) return; #endif
#if DBG
// DP2 HAL supports 16 bit indices only
if (pv->dwIndexSize != 2) { D3D_THROW_FAIL("Device does not support 32-bit indices"); } #endif
this->dwDP2Flags |= D3DDDI_INDEXEDPRIMDRAWN; DWORD dwByteCount; // Command length plus indices
DWORD dwIndicesByteCount; // Indices only
if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { m_pDevice->UpdateTextures(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } dwIndicesByteCount = pv->dwNumIndices << 1; dwByteCount = dwIndicesByteCount + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2STARTVERTEX);
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND) ReserveSpaceInCommandBuffer(dwByteCount); lpDP2CurrCommand->bReserved = 0; lpDP2CurrCommand->wPrimitiveCount = (WORD)pv->dwNumPrimitives;
LPBYTE pIndices = (BYTE*)(lpDP2CurrCommand + 1); // Place for indices
lpDP2CurrCommand->bCommand = (BYTE)iprim2cmdop[pv->primType]; WORD* pStartVertex = &((LPD3DHAL_DP2STARTVERTEX)(lpDP2CurrCommand+1))->wVStart; pIndices += sizeof(D3DHAL_DP2STARTVERTEX);
#if DBG
if (lpDP2CurrCommand->bCommand == 0) { D3D_THROW_FAIL("Illegal primitive type"); } #endif
bDP2CurrCmdOP = lpDP2CurrCommand->bCommand;
// We have to handle the case when we copied vertices into our
// TL buffer, so MinVertexIndex corresponds to 0.
*pStartVertex = (WORD)this->dwVertexBase; if (m_dwIndexOffset == 0) { memcpy(pIndices, pv->lpwIndices, dwIndicesByteCount); } else if ((WORD)dwVertexBase > (WORD)m_dwIndexOffset) { // We can modify StartVertex by setting it outside vertex range
*pStartVertex = (WORD)dwVertexBase - (WORD)m_dwIndexOffset; memcpy(pIndices, pv->lpwIndices, dwIndicesByteCount); } else { WORD* pout = (WORD*)pIndices; WORD* pin = (WORD*)pv->lpwIndices; for (UINT i=0; i < pv->dwNumIndices; i++) { pout[i] = (WORD)pin[i] - (WORD)m_dwIndexOffset; } }
wDP2CurrCmdCnt = lpDP2CurrCommand->wPrimitiveCount; dwDP2CommandLength += dwByteCount;
#if DBG
if (m_bValidateCommands) ValidateCommand(lpDP2CurrCommand); #endif
} //-----------------------------------------------------------------------------
// This primitive is generated by the clipper.
// The vertices of this primitive are pointed to by the
// lpvOut member, which need to be copied into the
// command stream immediately after the command itself.
//
// Uses the following members of D3DFE_PROCESSVERTICES:
// primType
// dwNumVertices
// dwNumPrimitives
// dwOutputSize
// dwFlags (D3DPV_NONCLIPPED)
// lpdwRStates (FILLMODE)
// lpvOut
// ClipperState.current_vbuf
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::DrawClippedPrim"
void CD3DDDIDX6::DrawClippedPrim(D3DFE_PROCESSVERTICES* pv) { #ifdef DEBUG_PIPELINE
if (g_DebugFlags & __DEBUG_NORENDERING) return; #endif
if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { m_pDevice->UpdateTextures(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } DWORD dwExtra = 0; LPVOID lpvVerticesImm; // Place for vertices
DWORD dwVertexPoolSize = pv->dwNumVertices * pv->dwOutputSize; if (pv->primType == D3DPT_TRIANGLEFAN) { if (pv->lpdwRStates[D3DRENDERSTATE_FILLMODE] == D3DFILL_WIREFRAME && pv->dwFlags & D3DPV_NONCLIPPED) { // For unclipped (but pretended to be clipped) tri fans in
// wireframe mode we generate 3-vertex tri fans to enable drawing
// of interior edges
BYTE vertices[__MAX_VERTEX_SIZE*3]; BYTE *pV1 = vertices + pv->dwOutputSize; BYTE *pV2 = pV1 + pv->dwOutputSize; BYTE *pInput = (BYTE*)pv->lpvOut; memcpy(vertices, pInput, pv->dwOutputSize); pInput += pv->dwOutputSize; const DWORD nTriangles = pv->dwNumVertices - 2; pv->dwNumVertices = 3; pv->dwNumPrimitives = 1; pv->lpvOut = vertices; // Remove this flag for recursive call
pv->dwFlags &= ~D3DPV_NONCLIPPED; for (DWORD i = nTriangles; i; i--) { memcpy(pV1, pInput, pv->dwOutputSize); memcpy(pV2, pInput + pv->dwOutputSize, pv->dwOutputSize); pInput += pv->dwOutputSize; // To enable all edge flag we set the fill mode to SOLID.
// This will prevent checking the clip flags in the clipper
// state
pv->lpdwRStates[D3DRENDERSTATE_FILLMODE] = D3DFILL_SOLID; DrawClippedPrim(pv); pv->lpdwRStates[D3DRENDERSTATE_FILLMODE] = D3DFILL_WIREFRAME; } return; } dwExtra = sizeof(D3DHAL_DP2TRIANGLEFAN_IMM); } DWORD dwPad; dwPad = (sizeof(D3DHAL_DP2COMMAND) + dwDP2CommandLength + dwExtra) & 3; DWORD dwByteCount = sizeof(D3DHAL_DP2COMMAND) + dwPad + dwExtra + dwVertexPoolSize;
// Check for space in the command buffer for commands & vertices
if (dwDP2CommandLength + dwByteCount > dwDP2CommandBufSize) { // Flush the current batch but hold on to the vertices
FlushStates(FALSE,TRUE); if (dwByteCount > dwDP2CommandBufSize) { GrowCommandBuffer(dwByteCount); }
dwPad = (sizeof(D3DHAL_DP2COMMAND) + dwExtra) & 3; dwByteCount = sizeof(D3DHAL_DP2COMMAND) + dwExtra + dwPad + dwVertexPoolSize; } lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->wPrimitiveCount = (WORD)pv->dwNumPrimitives; lpDP2CurrCommand->bReserved = 0; if (pv->primType == D3DPT_TRIANGLEFAN) { // Insert inline instruction and vertices
bDP2CurrCmdOP = D3DDP2OP_TRIANGLEFAN_IMM; lpDP2CurrCommand->bCommand = bDP2CurrCmdOP; LPD3DHAL_DP2TRIANGLEFAN_IMM lpTriFanImm; lpTriFanImm = (LPD3DHAL_DP2TRIANGLEFAN_IMM)(lpDP2CurrCommand + 1); if (pv->lpdwRStates[D3DRENDERSTATE_FILLMODE] == D3DFILL_WIREFRAME) { lpTriFanImm->dwEdgeFlags = 0; ClipVertex **clip = pv->ClipperState.current_vbuf; // Look at the exterior edges and mark the visible ones
for(DWORD i = 0; i < pv->dwNumVertices; ++i) { if (clip[i]->clip & CLIPPED_ENABLE) lpTriFanImm->dwEdgeFlags |= (1 << i); } } else { // Mark all exterior edges visible
lpTriFanImm->dwEdgeFlags = 0xFFFFFFFF; } lpvVerticesImm = (LPBYTE)(lpTriFanImm + 1) + dwPad; } else { // Insert inline instruction and vertices
bDP2CurrCmdOP = D3DDP2OP_LINELIST_IMM; lpDP2CurrCommand->bCommand = bDP2CurrCmdOP; lpvVerticesImm = (LPBYTE)(lpDP2CurrCommand + 1) + dwPad; } memcpy(lpvVerticesImm, pv->lpvOut, dwVertexPoolSize); dwDP2CommandLength += dwByteCount; #if DBG
if (m_bValidateCommands) ValidateCommand(lpDP2CurrCommand); #endif
} //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::PickProcessPrimitive"
void CD3DDDIDX6::PickProcessPrimitive() { D3DFE_PROCESSVERTICES* pv = static_cast<CD3DHal*>(m_pDevice)->m_pv; if (pv->dwDeviceFlags & D3DDEV_DOPOINTSPRITEEMULATION) { m_pfnProcessPrimitive = ProcessPointSprites; } else if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP) { // Transformed vertices should not be processed using
// m_pfnProcessPrimitive. They should go directly to the DDI using
// pDevice->m_pfnDrawPrim
m_pfnProcessPrimitive = ProcessPrimitive; m_pfnProcessIndexedPrimitive = ProcessIndexedPrimitive; } else { if (pv->dwDeviceFlags & D3DDEV_TRANSFORMEDFVF) { m_pfnProcessPrimitive = ProcessPrimitiveTC; m_pfnProcessIndexedPrimitive = ProcessIndexedPrimitiveTC; } else { m_pfnProcessPrimitive = ProcessPrimitiveC; m_pfnProcessIndexedPrimitive = ProcessIndexedPrimitiveC; } } } //-----------------------------------------------------------------------------
// The function does the point sprite expansion
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::ProcessPointSprites"
void CD3DDDIDX6::ProcessPointSprites(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice);
DWORD dwOldCullMode = D3DCULL_NONE; DWORD dwOldFillMode = D3DFILL_SOLID; // Point spritest should not be culled. They are generated assuming that
// D3DCULL_CCW is set
if (pDevice->rstates[D3DRS_CULLMODE] == D3DCULL_CW) { dwOldCullMode = D3DCULL_CW; SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); }
// In case of multitexture we need to re-program texture stages to use
// texture coordonate set 0, because we generate only one set during
// emulation
DWORD TexCoordIndex[D3DDP_MAXTEXCOORD]; for (DWORD i=0; i < D3DDP_MAXTEXCOORD; i++) { if (pDevice->tsstates[i][D3DTSS_COLOROP] == D3DTOP_DISABLE) break; if (pDevice->m_lpD3DMappedTexI[i]) { DWORD dwIndex = pDevice->tsstates[i][D3DTSS_TEXCOORDINDEX]; if (dwIndex != 0) { TexCoordIndex[i] = dwIndex; SetTSS(i, D3DTSS_TEXCOORDINDEX, 0); } else { // Mark stage to not restore
TexCoordIndex[i] = 0xFFFFFFFF; } } }
// Fill mode should be SOLID for point sprites
if (pDevice->rstates[D3DRS_FILLMODE] != D3DFILL_SOLID) { dwOldFillMode = pDevice->rstates[D3DRS_FILLMODE]; SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); } // Compute new output FVF
m_dwVIDOutPS = pv->dwVIDOut; m_dwVIDOutPS &= ~D3DFVF_PSIZE; if (pv->lpdwRStates[D3DRS_POINTSPRITEENABLE]) { // Generate two floats for texture coord set
m_dwVIDOutPS &= 0xFF; m_dwVIDOutPS |= D3DFVF_TEX1; } m_dwOutputSizePS = ComputeVertexSizeFVF(m_dwVIDOutPS);
StartPointSprites();
UINT VertexPoolSize = pv->dwNumVertices * pv->dwOutputSize;
if (pv->dwDeviceFlags & D3DDEV_TRANSFORMEDFVF) { // In case of transformed vertices, input is user memory (or vertex
// buffer) and the output is internal TL buffer
pv->dwOutputSize = pv->position.dwStride; if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP) { pv->lpvOut = (BYTE*)pv->position.lpvData; DrawPrim(pv); } else { if (!(pv->dwDeviceFlags & D3DDEV_DONOTCOMPUTECLIPCODES)) PrepareForClipping(pv, StartVertex); pv->lpvOut = (BYTE*)pv->position.lpvData; HRESULT ret = D3D_OK; if (!(pv->dwDeviceFlags & D3DDEV_VBPROCVER)) { // Compute clip codes, because there was no ProcessVertices
DWORD clip_intersect = D3DFE_GenClipFlags(pv); UpdateClipStatus(pDevice); if (clip_intersect) { goto l_exit; } // There are some vertices inside the screen
if ( CheckIfNeedClipping(pv)) ret = ProcessClippedPointSprites(pv); else DrawPrim(pv); } else { // With the result of ProcessVertices as input we do not know
// clip union, so we need always do clipping
ret = ProcessClippedPointSprites(pv); }
if (ret != D3D_OK) { EndPointSprites(); throw ret; } } } else { if (!(pv->dwDeviceFlags & D3DDEV_DONOTCLIP)) PrepareForClipping(pv, 0);
// Update lighting and related flags
if (pDevice->dwFEFlags & D3DFE_FRONTEND_DIRTY) DoUpdateState(pDevice);
UINT VertexPoolSize = pv->dwNumVertices * pv->dwOutputSize; pv->lpvOut = m_pPointStream->Lock(VertexPoolSize, this);
// We call ProcessVertices instead of DrawPrimitive, because we want to
// process sprites which are clippied by X or Y planes
DWORD clipIntersection = pv->pGeometryFuncs->ProcessVertices(pv);
HRESULT ret = D3D_OK; if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP) { DrawPrim(pv); } else { // We throw away points which are clipped by Z or by user planes.
// Otherwise a point sprite could be partially visible
clipIntersection &= ~(D3DCS_LEFT | D3DCS_RIGHT | D3DCS_TOP | D3DCS_BOTTOM | __D3DCLIPGB_ALL); if (!clipIntersection) { // There are some vertices inside the screen
if (!CheckIfNeedClipping(pv)) DrawPrim(pv); else ret = ProcessClippedPointSprites(pv); } }
m_pPointStream->Unlock(); m_pPointStream->Reset(); if (ret != D3D_OK) D3D_THROW(ret, "Error in PSGP");
if (!(pv->dwDeviceFlags & D3DDEV_DONOTCLIP)) UpdateClipStatus(pDevice); } l_exit: EndPointSprites(); // Restore fill mode and cull mode if needed
if (dwOldCullMode != D3DCULL_NONE) { SetRenderState(D3DRS_CULLMODE, dwOldCullMode); } if (dwOldFillMode != D3DFILL_SOLID) { SetRenderState(D3DRS_FILLMODE, dwOldFillMode); } // We need to re-send API vertex shader to the driver next time
// SetVertexShader is called. If we do not call the function then next
// the same SetVertexShader call will be ignored and driver vertex shader
// will not be updated
static_cast<CD3DHal*>(m_pDevice)->ForceFVFRecompute();
// Now we need to restore re-programmed stages
for (DWORD i=0; i < D3DDP_MAXTEXCOORD; i++) { if (pDevice->tsstates[i][D3DTSS_COLOROP] == D3DTOP_DISABLE) break; if (pDevice->m_lpD3DMappedTexI[i] && TexCoordIndex[i] != 0xFFFFFFFF) { this->SetTSS(i, D3DTSS_TEXCOORDINDEX, TexCoordIndex[i]); } } } //-----------------------------------------------------------------------------
// Processes non-indexed primitives with transformed vertices and with
// clipping
//
// Only transformed vertices generated by ProcessVertices call are allowed here
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::ProcessPrimitiveTC"
void CD3DDDIDX6::ProcessPrimitiveTC(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice); CVStream* pStream = &m_pDevice->m_pStream[0];
PrepareForClipping(pv, StartVertex);
pv->dwOutputSize = pStream->m_dwStride; pv->lpvOut = pv->position.lpvData;
if (m_pDevice->m_dwRuntimeFlags & D3DRT_USERMEMPRIMITIVE) { DXGASSERT(StartVertex == 0); // Copy vertices to the TL buffer
UINT VertexPoolSize = pv->dwOutputSize * pv->dwNumVertices; pv->lpvOut = (BYTE*)StartPrimTL(pv, VertexPoolSize, FALSE); pv->position.lpvData = pv->lpvOut; memcpy(pv->lpvOut, m_pDevice->m_pStream[0].m_pData, VertexPoolSize); } else StartPrimVB(pv, pStream, StartVertex); if (!(pv->dwDeviceFlags & D3DDEV_VBPROCVER)) { pv->dwFlags |= D3DPV_TLVCLIP; // Compute clip codes, because there was no ProcessVertices
DWORD clip_intersect = D3DFE_GenClipFlags(pDevice->m_pv); UpdateClipStatus(pDevice); if (clip_intersect) goto l_exit; } HRESULT ret = pDevice->GeometryFuncsGuaranteed->DoDrawPrimitive(pv); if (ret != D3D_OK) { EndPrim(pv->dwOutputSize); throw ret; } l_exit: EndPrim(pv->dwOutputSize); pv->dwFlags &= ~D3DPV_TLVCLIP; } //-----------------------------------------------------------------------------
// Processes non-indexed primitives with untransformed vertices and with
// clipping
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::ProcessPrimitiveC"
void CD3DDDIDX6::ProcessPrimitiveC(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW);
CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice); PrepareForClipping(pv, 0); // Update lighting and related flags
if (pDevice->dwFEFlags & D3DFE_FRONTEND_DIRTY) DoUpdateState(pDevice); // When a triangle strip is clipped, we draw indexed primitives
// sometimes. So we set m_dwIndexOffset to zero.
m_dwIndexOffset = 0; UINT VertexPoolSize = pv->dwNumVertices * pv->dwOutputSize; pv->lpvOut = StartPrimTL(pv, VertexPoolSize, TRUE);
HRESULT ret = pv->pGeometryFuncs->ProcessPrimitive(pv); if (ret != D3D_OK) { EndPrim(pv->dwOutputSize); D3D_THROW(ret, "Error in PSGP"); } EndPrim(pv->dwOutputSize); UpdateClipStatus(pDevice); } //-----------------------------------------------------------------------------
// Processes non-indexed primitives with untransformed vertices and without
// clipping
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::ProcessPrimitive"
void CD3DDDIDX6::ProcessPrimitive(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW);
CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice); // Update lighting and related flags
if (pDevice->dwFEFlags & D3DFE_FRONTEND_DIRTY) DoUpdateState(pDevice);
UINT VertexPoolSize = pv->dwNumVertices * pv->dwOutputSize; pv->lpvOut = StartPrimTL(pv, VertexPoolSize, NeverReadFromTLBuffer(pv));
HRESULT ret = pv->pGeometryFuncs->ProcessPrimitive(pv); if (ret != D3D_OK) { EndPrim(pv->dwOutputSize); D3D_THROW(ret, "Error in PSGP"); } EndPrim(pv->dwOutputSize); } //-----------------------------------------------------------------------------
// Processes indexed primitive with untransformed vertices and without clipping
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::ProcessIndexedPrimitive"
void CD3DDDIDX6::ProcessIndexedPrimitive(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice);
// Update lighting and related flags
if (pDevice->dwFEFlags & D3DFE_FRONTEND_DIRTY) DoUpdateState(pDevice);
pv->lpwIndices = (WORD*)(pDevice->m_pIndexStream->Data() + m_StartIndex * pDevice->m_pIndexStream->m_dwStride);
m_dwIndexOffset = m_MinVertexIndex; pv->lpvOut = StartPrimTL(pv, pv->dwNumVertices * pv->dwOutputSize, TRUE); AddVertices(pv->dwNumVertices);
HRESULT ret = pv->pGeometryFuncs->ProcessIndexedPrimitive(pv);
MovePrimitiveBase(pv->dwNumVertices); EndPrim(pv->dwOutputSize);
if (ret != D3D_OK) D3D_THROW(ret, "Error in PSGP"); } //-----------------------------------------------------------------------------
// Processes indexed primitive with untransformed vertices and witht clipping
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::ProcessIndexedPrimitiveC"
void CD3DDDIDX6::ProcessIndexedPrimitiveC(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW);
CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice); pv->lpwIndices = (WORD*)(pDevice->m_pIndexStream->Data() + m_StartIndex * pDevice->m_pIndexStream->m_dwStride);
PrepareForClipping(pv, 0);
// Update lighting and related flags
if (pDevice->dwFEFlags & D3DFE_FRONTEND_DIRTY) DoUpdateState(pDevice);
pv->dwIndexOffset = m_MinVertexIndex; // For clipping
m_dwIndexOffset = m_MinVertexIndex; // For DrawIndexPrim
pv->lpvOut = StartPrimTL(pv, pv->dwNumVertices * pv->dwOutputSize, FALSE); DWORD dwNumVertices = pv->dwNumVertices; AddVertices(pv->dwNumVertices);
this->dwDP2Flags &= ~D3DDDI_INDEXEDPRIMDRAWN;
HRESULT ret = pv->pGeometryFuncs->ProcessIndexedPrimitive(pv);
if (this->dwDP2Flags & D3DDDI_INDEXEDPRIMDRAWN) { // There was a indexed primitive drawn
MovePrimitiveBase(dwNumVertices); } else { // All triangle were clipped. Remove vertices from TL buffer
SubVertices(dwNumVertices); } EndPrim(pv->dwOutputSize); UpdateClipStatus(pDevice);
if (ret != D3D_OK) D3D_THROW(ret, "Error in PSGP"); } //-----------------------------------------------------------------------------
// Processes indexed primitive with transformed vertices and with clipping
//
// Only transformed vertices generated by ProcessVertices call are allowed here
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::ProcessIndexedPrimitiveTC"
void CD3DDDIDX6::ProcessIndexedPrimitiveTC(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { HRESULT ret = S_OK; CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice); CVStream* pStream = &m_pDevice->m_pStream[0]; pv->lpwIndices = (WORD*)(pDevice->m_pIndexStream->Data() + m_StartIndex * pDevice->m_pIndexStream->m_dwStride);
PrepareForClipping(pv, StartVertex);
pv->dwOutputSize = pStream->m_dwStride; pv->lpvOut = pv->position.lpvData; pv->dwNumVertices = m_MinVertexIndex + m_NumVertices;
if (m_pDevice->m_dwRuntimeFlags & D3DRT_USERMEMPRIMITIVE) { // We copy user vertices, starting from MinVertexIndex, to the internal
// TL buffer and do the clipping. Vertex base changes in the process.
// m_NumVertices has been computed as MinVertexIndex + NumVertices, so
// it needs to be adjusted, because vertex base has benn changed
m_NumVertices -= m_MinVertexIndex; pv->dwNumVertices = m_NumVertices; // Copy vertices to the TL buffer
UINT VertexPoolSize = pv->dwOutputSize * pv->dwNumVertices; pv->lpvOut = (BYTE*)StartPrimTL(pv, VertexPoolSize, FALSE); pv->position.lpvData = pv->lpvOut; memcpy(pv->lpvOut, m_pDevice->m_pStream[0].m_pData + m_MinVertexIndex * pv->dwOutputSize, VertexPoolSize); // Pre-DX8 DDI does not have BaseVertexIndex parameter, so we need to
// re-compute indices before passing them to the driver to reflect
// the changed vertex base
m_dwIndexOffset = m_MinVertexIndex ; } else { StartPrimVB(pv, pStream, m_BaseVertexIndex); m_dwIndexOffset = 0; // For DrawIndexPrim
}
pv->dwNumVertices = m_NumVertices;
if (!(pv->dwDeviceFlags & D3DDEV_VBPROCVER)) { pv->dwFlags |= D3DPV_TLVCLIP; // Compute clip codes, because there was no ProcessVertices
DWORD clip_intersect = D3DFE_GenClipFlags(pv); UpdateClipStatus(pDevice); if (clip_intersect) goto l_exit; } pv->dwIndexOffset = m_MinVertexIndex ; // For clipping
this->dwDP2Flags &= ~D3DDDI_INDEXEDPRIMDRAWN; DWORD dwNumVertices = pv->dwNumVertices; AddVertices(pv->dwNumVertices);
ret = pDevice->GeometryFuncsGuaranteed->DoDrawIndexedPrimitive(pv);
if (this->dwDP2Flags & D3DDDI_INDEXEDPRIMDRAWN) { // There was an indexed primitive drawn
MovePrimitiveBase(dwNumVertices); } else { // All triangles were clipped. Remove vertices from TL buffer
SubVertices(dwNumVertices); } l_exit: pv->dwFlags &= ~D3DPV_TLVCLIP; EndPrim(pv->dwOutputSize); UpdateClipStatus(pDevice); if (ret != D3D_OK) throw ret; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::GrowCommandBuffer"
// Check and grow command buffer
void CD3DDDIDX6::GrowCommandBuffer(DWORD dwSize) { HRESULT ret; if (dwSize > dwDP2CommandBufSize) { if (lpDDSCB1) { lpDDSCB1->DecrementUseCount(); lpDDSCB1 = NULL; } // Create command buffer through Framework.
// NOTE: Command buffers are always REF_INTERNAL
// objects and must be released through
// DecrementUseCount
//
ret = CCommandBuffer::Create(m_pDevice, dwSize, D3DPOOL_SYSTEMMEM, &lpDDSCB1); if (ret != DD_OK) { dwDP2CommandBufSize = 0; D3D_THROW(ret, "Failed to allocate Command Buffer"); } // Lock command buffer
ret = lpDDSCB1->Lock(0, dwSize, (BYTE**)&lpvDP2Commands, NULL); if (ret != DD_OK) { lpDDSCB1->DecrementUseCount(); lpDDSCB1 = NULL; dwDP2CommandBufSize = 0; D3D_THROW(ret, "Could not lock command buffer"); } // lpDDCommands will be filled in by the thunk layer
dp2data.hDDCommands = lpDDSCB1->DriverAccessibleKernelHandle(); dwDP2CommandBufSize = dwSize; } } //-----------------------------------------------------------------------------
// This function prepares the batch for new primitive.
// Called if vertices from user memory are used for rendering
//
// If bWriteOnly is set to TRUE, then there will be no read from the vertex
// processing output (no clipping or TL HAL).
//
// Expects the following members of D3DFE_PROCESSVERTICES to be initialized
// dwNumVertices
// lpvOut
// dwOutputSize
// dwVIDOut
//
// We fail vid mem VB for clipping
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::StartPrimUserMem"
void CD3DDDIDX6::StartPrimUserMem(D3DFE_PROCESSVERTICES* pv, UINT VertexPoolSize) { // If the primitive is small, we copy vertices into the TL buffer
if (pv->dwNumVertices < LOWVERTICESNUMBER) { LPVOID tmp = StartPrimTL(pv, VertexPoolSize, TRUE); memcpy(tmp, pv->lpvOut, VertexPoolSize); this->dwDP2VertexCount += pv->dwNumVertices; } else { // We can not mix user memory primitive with other primitives, so
// flush the batch.
// Do not forget to flush the batch after rendering this primitive
this->FlushStates();
SetWithinPrimitive( TRUE ); // Release previously used vertex buffer (if any), because we do not
// it any more
if (lpDP2CurrBatchVBI) { lpDP2CurrBatchVBI->DecrementUseCount(); lpDP2CurrBatchVBI = NULL; } dp2data.dwVertexType = pv->dwVIDOut; dp2data.dwVertexSize = pv->dwOutputSize; dp2data.lpVertices = pv->lpvOut; dp2data.dwFlags |= D3DHALDP2_USERMEMVERTICES; dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER; this->dwDP2Flags |= D3DDDI_USERMEMVERTICES; this->dwDP2VertexCount = pv->dwNumVertices; this->dwDP2VertexCountMask = 0; } } //-----------------------------------------------------------------------------
// This function prepares the batch for new primitive.
// Called only if vertices from user memory are NOT used for rendering
//
// Uses the following data from D3DFE_PROCESSVERTICES:
// pv->dwVIDOut
// pv->dwOutputSize
// pv->dwNumVertices
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::StartPrimVB"
void CD3DDDIDX6::StartPrimVB(D3DFE_PROCESSVERTICES * pv, CVStream* pStream, DWORD dwStartVertex) { CVertexBuffer * lpVBI = pStream->m_pVB; // If VID has been changed or new vertex buffer is used we flush the batch
if (pv->dwVIDOut != dp2data.dwVertexType || lpDP2CurrBatchVBI != lpVBI) { this->FlushStates(); dp2data.dwVertexType = pv->dwVIDOut; dp2data.dwVertexSize = pv->dwOutputSize; dp2data.hDDVertex = lpVBI->DriverAccessibleKernelHandle(); // Release previously used vertex buffer (if any), because we do not
// need it any more. We did IncrementUseCount() to TL buffer,
// so it is safe.
if (lpDP2CurrBatchVBI) { lpDP2CurrBatchVBI->DecrementUseCount(); } // If a vertex buffer is used for rendering, make sure that it is no
// released by user. So do IncrementUseCount().
lpDP2CurrBatchVBI = lpVBI; lpDP2CurrBatchVBI->IncrementUseCount(); } DXGASSERT(dp2data.hDDVertex == lpVBI->DriverAccessibleKernelHandle()); lpDP2CurrBatchVBI->Batch(); SetWithinPrimitive( TRUE ); this->dwVertexBase = dwStartVertex; dp2data.dwFlags &= ~D3DHALDP2_SWAPVERTEXBUFFER; this->dwDP2VertexCount = max(this->dwDP2VertexCount, this->dwVertexBase + pv->dwNumVertices); // Prevent modification of dwDP2VertexCount during DrawPrim
this->dwDP2VertexCountMask = 0; } //-----------------------------------------------------------------------------
// This function prepares the batch for new primitive.
// Called when the runtime needs to output vertices to a TL buffer
// TL buffer grows if necessary
//
// Uses the following global variables:
// pv->dwVIDOut
// pv->dwNumVertices
// this->dp2data
// this->dwDP2VertexCount;
// this->lpDP2CurrBatchVBI
// this->dwDP2Flags
// pv->dwOutputSize
// Updates the following variables:
// this->dwVertexBase
// this->dwDP2VertexCount;
// this->lpDP2CurrBatchVBI
// dp2data.dwFlags
// Sets "within primitive" to TRUE
// Returns:
// TL buffer address
//
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::StartPrimTL"
LPVOID CD3DDDIDX6::StartPrimTL(D3DFE_PROCESSVERTICES * pv, DWORD dwVertexPoolSize, BOOL bWriteOnly) { if (bWriteOnly) { if (dwVertexPoolSize > this->GetTLVbufSize()) { this->GrowTLVbuf(dwVertexPoolSize, TRUE); } } else { if (this->dwDP2Flags & D3DDDI_TLVBUFWRITEONLY || dwVertexPoolSize > this->GetTLVbufSize()) { this->GrowTLVbuf(dwVertexPoolSize, FALSE); } }
CVertexBuffer * lpVBI = this->TLVbuf_GetVBI();
// If VID has been changed or new vertex buffer is used we flush the batch
if (pv->dwVIDOut != dp2data.dwVertexType || lpDP2CurrBatchVBI != lpVBI || dp2data.hDDVertex != lpVBI->DriverAccessibleKernelHandle()) { this->FlushStates(); dp2data.dwVertexType = pv->dwVIDOut; dp2data.dwVertexSize = pv->dwOutputSize; dp2data.hDDVertex = lpVBI->DriverAccessibleKernelHandle(); // Release previously used vertex buffer (if any), because we do not
// need it any more. We did IncrementUseCount() to TL buffer,
// so it is safe.
if (lpDP2CurrBatchVBI) { lpDP2CurrBatchVBI->DecrementUseCount(); } // If a vertex buffer is used for rendering, make sure that it is not
// released by user. So do IncrementUseCount().
lpDP2CurrBatchVBI = lpVBI; lpDP2CurrBatchVBI->IncrementUseCount(); } SetWithinPrimitive( TRUE ); this->dwVertexBase = this->dwDP2VertexCount; DDASSERT(this->dwVertexBase < MAX_DX6_VERTICES); dp2data.dwFlags |= D3DHALDP2_SWAPVERTEXBUFFER; this->dwDP2VertexCountMask = 0xFFFFFFFF;
return this->TLVbuf_GetAddress(); } //---------------------------------------------------------------------
// This function should not be called from DrawVertexBufferVB
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::EndPrim"
void CD3DDDIDX6::EndPrim(UINT vertexSize) { // Should be called before the FlushStates
SetWithinPrimitive(FALSE); if (this->dwDP2Flags & D3DDDI_USERMEMVERTICES) // We can not mix user memory primitive, so flush it.
{ FlushStates(); this->dwDP2Flags &= ~D3DDDI_USERMEMVERTICES; } else if (lpDP2CurrBatchVBI == this->TLVbuf_GetVBI()) { // If TL buffer was used, we have to move its internal base pointer
this->TLVbuf_Base() = this->dwDP2VertexCount * vertexSize; #if DBG
if (this->TLVbuf_base > this->TLVbuf_size) { D3D_THROW(D3DERR_INVALIDCALL, "Internal error: TL buffer error"); } #endif
} } //----------------------------------------------------------------------
// Growing aligned vertex buffer implementation.
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::GrowTLVbuf"
void CD3DDDIDX6::GrowTLVbuf(DWORD growSize, BOOL bWriteOnly) { CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice); DWORD dwRefCnt = 1; // Is ref cnt of TLVbuf 1 or 2 ?
DWORD bTLVbufIsCurr = this->allocatedBuf == this->lpDP2CurrBatchVBI;
BOOL bDP2WriteOnly = (dwDP2Flags & D3DDDI_TLVBUFWRITEONLY) != 0; // Avoid to many changes. Restrict TLVbuf to sys mem if too many changes
if (this->dwTLVbufChanges >= D3D_MAX_TLVBUF_CHANGES) { #if DBG
if (this->dwTLVbufChanges == D3D_MAX_TLVBUF_CHANGES) DPF(1, "Too many changes: Limiting internal VB to sys mem."); #endif
bWriteOnly = FALSE; } if (this->TLVbuf_base || (bWriteOnly != bDP2WriteOnly)) { FlushStatesReq(growSize); this->TLVbuf_base = 0; } if (growSize <= this->TLVbuf_size) { if (bWriteOnly == bDP2WriteOnly) return; else this->dwTLVbufChanges++; } if (this->allocatedBuf) { this->allocatedBuf->DecrementUseCount(); this->allocatedBuf = NULL; } if (bTLVbufIsCurr) { if (this->lpDP2CurrBatchVBI) this->lpDP2CurrBatchVBI->DecrementUseCount(); this->lpDP2CurrBatchVBI = NULL; this->dp2data.lpVertices = NULL; } DWORD dwNumVerts = (max(growSize, TLVbuf_size) + 31) / sizeof(D3DTLVERTEX); this->TLVbuf_size = dwNumVerts * sizeof(D3DTLVERTEX); D3DPOOL Pool = D3DPOOL_DEFAULT; DWORD dwUsage = D3DUSAGE_INTERNALBUFFER | D3DUSAGE_DYNAMIC; if (bWriteOnly) { dwUsage |= D3DUSAGE_WRITEONLY; dwDP2Flags |= D3DDDI_TLVBUFWRITEONLY; } else { dwDP2Flags &= ~D3DDDI_TLVBUFWRITEONLY; } LPDIRECT3DVERTEXBUFFER8 t; HRESULT ret = CVertexBuffer::Create(pDevice, this->TLVbuf_size, dwUsage, D3DFVF_TLVERTEX, Pool, REF_INTERNAL, &t); // This should fail duirng ulta-low memory situations.
if (ret != DD_OK) { // We set allocatedBuf to a valid VB object since it gets dereferenced many places without
// checking for it being NULL. WE use the special "NULL" VB created at init time for just
// this purpose
allocatedBuf = m_pNullVB; if (m_pNullVB) // We do this check because GrowTLVbuf will be called before m_pNullVB is set first time round.
{ allocatedBuf->IncrementUseCount(); // Update lpDP2CurrentBatchVBI if necessary
if (bTLVbufIsCurr) { lpDP2CurrBatchVBI = allocatedBuf; lpDP2CurrBatchVBI->IncrementUseCount(); dp2data.hDDVertex = lpDP2CurrBatchVBI->DriverAccessibleKernelHandle(); } } this->TLVbuf_size = 0; this->alignedBuf = NULL; // Lets see if some one tries to use this...
D3D_THROW(ret, "Could not allocate internal vertex buffer"); } allocatedBuf = static_cast<CVertexBuffer*>(t); ret = allocatedBuf->Lock(0, this->TLVbuf_size, (BYTE**)&alignedBuf, 0); if (ret != DD_OK) { TLVbuf_size = 0; alignedBuf = NULL; // Lets see if some one tries to use this...
D3D_THROW(ret, "Could not lock internal vertex buffer"); } // Update lpDP2CurrentBatchVBI if necessary
if (bTLVbufIsCurr) { lpDP2CurrBatchVBI = allocatedBuf; lpDP2CurrBatchVBI->IncrementUseCount(); dp2data.hDDVertex = lpDP2CurrBatchVBI->DriverAccessibleKernelHandle(); } } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::Clear"
void CD3DDDIDX6::Clear(DWORD dwFlags, DWORD clrCount, LPD3DRECT clrRects, D3DCOLOR dwColor, D3DVALUE dvZ, DWORD dwStencil) { HRESULT err; // Flush any outstanding geometry to put framebuffer/Zbuffer in a known
// state for Clears that don't use tris (i.e. HAL Clears and Blts).
// Note this doesn't work for tiled architectures
// outside of Begin/EndScene, this will be fixed later
FlushStates();
// Clear2 HAL Callback exists
D3D8_CLEAR2DATA Clear2Data; Clear2Data.dwhContext = m_dwhContext; Clear2Data.dwFlags = dwFlags; // Here I will follow the ClearData.dwFillColor convention that
// color word is raw 32bit ARGB, unadjusted for surface bit depth
Clear2Data.dwFillColor = dwColor; // depth/stencil values both passed straight from user args
Clear2Data.dvFillDepth = dvZ; Clear2Data.dwFillStencil= dwStencil; Clear2Data.lpRects = clrRects; Clear2Data.dwNumRects = clrCount; Clear2Data.ddrval = D3D_OK; Clear2Data.hDDS = m_pDevice->RenderTarget()->KernelHandle(); if(m_pDevice->ZBuffer() != 0) { Clear2Data.hDDSZ = m_pDevice->ZBuffer()->KernelHandle(); } else { Clear2Data.hDDSZ = NULL; } err = m_pDevice->GetHalCallbacks()->Clear2(&Clear2Data); if (err != DDHAL_DRIVER_HANDLED) { D3D_THROW(E_NOTIMPL, "Driver does not support Clear"); } else if (Clear2Data.ddrval != DD_OK) { D3D_THROW(Clear2Data.ddrval, "Error in Clear"); } else return; }
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::LockVB"
HRESULT __declspec(nothrow) CD3DDDIDX6::LockVB(CDriverVertexBuffer *pVB, DWORD dwFlags) { if(pVB->GetCachedDataPointer() == 0) { HRESULT hr = pVB->LockI((dwFlags & D3DLOCK_DISCARD) | D3DLOCK_NOSYSLOCK); if(FAILED(hr)) { DPF_ERR("Driver failed to lock a vertex buffer" " when attempting to cache the lock."); return hr; } DXGASSERT(pVB->GetCachedDataPointer() != 0); } else { DXGASSERT((dwFlags & (D3DLOCK_READONLY | D3DLOCK_NOOVERWRITE)) == 0); // We CANNOT use the usual Sync check here (ie Device->BatchNumber <= pVB->BatchNumber)
// since there are situations in which this condition is true, but the VB is not really
// batched at all! This is the case for instance, when StartPrimVB calls FlushStates.
// FlushStates rebatches the current VB but StartPrimVB then switches to a new one. So
// both new and old "appear" batched, but only one of them is. This would be harmless
// (as it is for textures), were it not for the fact that we call FlushStatesReq to
// swap the pointer. When we call FlushStatesReq on an unbatched VB, we pretty much
// swap a random pointer with very bad effects. This repros in the Unreal driver. (snene)
if(static_cast<CVertexBuffer*>(pVB) == lpDP2CurrBatchVBI) { try { if((dwFlags & D3DLOCK_DISCARD) != 0) { FlushStatesReq(pVB->GetBufferDesc()->Size); } else { FlushStates(); } } catch(HRESULT hr) { DPF_ERR("Driver failed the command batch submitted to it" " when attempting to swap the current pointer" " in response to D3DLOCK_DISCARDCONTENTS."); pVB->SetCachedDataPointer(0); return hr; } DXGASSERT(pVB->GetCachedDataPointer() != 0); } } return D3D_OK; }
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::UnlockVB"
HRESULT __declspec(nothrow) CD3DDDIDX6::UnlockVB(CDriverVertexBuffer *pVB) { return D3D_OK; } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::EndScene"
void CD3DDDIDX6::EndScene() { this->dwTLVbufChanges = 0; // reset this every frame
SceneCapture(FALSE); }
/////////////////////////////////////////////////////////////////////////////
// //
// CD3DDDIDX7 //
// //
/////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
CD3DDDIDX7::CD3DDDIDX7() : CD3DDDIDX6() { m_ddiType = D3DDDITYPE_DX7; } //-----------------------------------------------------------------------------
CD3DDDIDX7::~CD3DDDIDX7() { return; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX7::SetRenderTarget"
void CD3DDDIDX7::SetRenderTarget(CBaseSurface *pTarget, CBaseSurface* pZBuffer) { LPD3DHAL_DP2SETRENDERTARGET pData; pData = (LPD3DHAL_DP2SETRENDERTARGET) GetHalBufferPointer(D3DDP2OP_SETRENDERTARGET, sizeof(*pData)); pData->hRenderTarget = pTarget->DrawPrimHandle(); if (pZBuffer) pData->hZBuffer = pZBuffer->DrawPrimHandle(); else pData->hZBuffer = 0; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX7::TexBlt"
void CD3DDDIDX7::TexBlt(DWORD dwDst, DWORD dwSrc, LPPOINT p, RECTL *r) { 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 = dwDst; lpTexBlt->dwDDSrcSurface = dwSrc; lpTexBlt->pDest = *p; lpTexBlt->rSrc = *r; lpTexBlt->dwFlags = 0; dwDP2CommandLength += sizeof(D3DHAL_DP2TEXBLT); #ifndef _IA64_
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
return; } } // Check for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TEXBLT) > dwDP2CommandBufSize) { FlushStates(); } // 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; #ifndef _IA64_
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
// Add texture blt data
LPD3DHAL_DP2TEXBLT lpTexBlt = (LPD3DHAL_DP2TEXBLT)(lpDP2CurrCommand + 1); lpTexBlt->dwDDDestSurface = dwDst; lpTexBlt->dwDDSrcSurface = dwSrc; lpTexBlt->pDest = *p; lpTexBlt->rSrc = *r; lpTexBlt->dwFlags = 0; dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2TEXBLT);
return; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX7::InsertStateSetOp"
void CD3DDDIDX7::InsertStateSetOp(DWORD dwOperation, DWORD dwParam, D3DSTATEBLOCKTYPE sbt) { LPD3DHAL_DP2STATESET pData; pData = (LPD3DHAL_DP2STATESET)GetHalBufferPointer(D3DDP2OP_STATESET, sizeof(*pData)); pData->dwOperation = dwOperation; pData->dwParam = dwParam; pData->sbType = sbt; } //---------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX7::SceneCapture"
void CD3DDDIDX7::SceneCapture(BOOL bState) { SetRenderState((D3DRENDERSTATETYPE)D3DRENDERSTATE_SCENECAPTURE, bState); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX7::SetPriority"
void CD3DDDIDX7::SetPriority(CResource *pRes, DWORD dwPriority) { DXGASSERT(pRes->BaseDrawPrimHandle() == pRes->DriverAccessibleDrawPrimHandle());
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 = pRes->BaseDrawPrimHandle(); lpSetPriority->dwPriority = dwPriority; dwDP2CommandLength += sizeof(D3DHAL_DP2SETPRIORITY); #ifndef _IA64_
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
pRes->BatchBase(); return; } } // Check for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2SETPRIORITY) > dwDP2CommandBufSize) { FlushStates(); } // 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; #ifndef _IA64_
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
// Add texture blt data
LPD3DHAL_DP2SETPRIORITY lpSetPriority = (LPD3DHAL_DP2SETPRIORITY)(lpDP2CurrCommand + 1); lpSetPriority->dwDDSurface = pRes->BaseDrawPrimHandle(); lpSetPriority->dwPriority = dwPriority; dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2SETPRIORITY);
pRes->BatchBase(); return; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX7::SetTexLOD"
void CD3DDDIDX7::SetTexLOD(CBaseTexture *pTex, DWORD dwLOD) { DXGASSERT(pTex->BaseDrawPrimHandle() == pTex->DriverAccessibleDrawPrimHandle());
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 = pTex->BaseDrawPrimHandle(); lpSetTexLOD->dwLOD = dwLOD; dwDP2CommandLength += sizeof(D3DHAL_DP2SETTEXLOD); #ifndef _IA64_
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
pTex->BatchBase(); return; } } // Check for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2SETTEXLOD) > dwDP2CommandBufSize) { FlushStates(); } // 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; #ifndef _IA64_
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
// Add texture blt data
LPD3DHAL_DP2SETTEXLOD lpSetTexLOD = (LPD3DHAL_DP2SETTEXLOD)(lpDP2CurrCommand + 1); lpSetTexLOD->dwDDSurface = pTex->BaseDrawPrimHandle(); lpSetTexLOD->dwLOD = dwLOD; dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2SETTEXLOD);
pTex->BatchBase(); return; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX7::AddDirtyRect"
void CD3DDDIDX7::AddDirtyRect(DWORD dwHandle, CONST RECTL *pRect) { if (bDP2CurrCmdOP == D3DDP2OP_ADDDIRTYRECT) { // Last instruction is a adddirtyrect, append this one to it
if (dwDP2CommandLength + sizeof(D3DHAL_DP2ADDDIRTYRECT) <= dwDP2CommandBufSize) { LPD3DHAL_DP2ADDDIRTYRECT lpDirtyRect = (LPD3DHAL_DP2ADDDIRTYRECT)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt; lpDirtyRect->dwSurface = dwHandle; lpDirtyRect->rDirtyArea = *pRect; dwDP2CommandLength += sizeof(D3DHAL_DP2ADDDIRTYRECT); #ifndef _IA64_
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
return; } } // Check for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2ADDDIRTYRECT) > dwDP2CommandBufSize) { FlushStates(); } // Add new renderstate instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->bCommand = D3DDP2OP_ADDDIRTYRECT; bDP2CurrCmdOP = D3DDP2OP_ADDDIRTYRECT; lpDP2CurrCommand->bReserved = 0; lpDP2CurrCommand->wStateCount = 1; wDP2CurrCmdCnt = 1; #ifndef _IA64_
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
// Add adddirtyrect data
LPD3DHAL_DP2ADDDIRTYRECT lpDirtyRect = (LPD3DHAL_DP2ADDDIRTYRECT)(lpDP2CurrCommand + 1); lpDirtyRect->dwSurface = dwHandle; lpDirtyRect->rDirtyArea = *pRect; dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2ADDDIRTYRECT);
return; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX7::AddDirtyBox"
void CD3DDDIDX7::AddDirtyBox(DWORD dwHandle, CONST D3DBOX *pBox) { if (bDP2CurrCmdOP == D3DDP2OP_ADDDIRTYBOX) { // Last instruction is a adddirtybox, append this one to it
if (dwDP2CommandLength + sizeof(D3DHAL_DP2ADDDIRTYBOX) <= dwDP2CommandBufSize) { LPD3DHAL_DP2ADDDIRTYBOX lpDirtyBox = (LPD3DHAL_DP2ADDDIRTYBOX)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt; lpDirtyBox->dwSurface = dwHandle; lpDirtyBox->DirtyBox = *pBox; dwDP2CommandLength += sizeof(D3DHAL_DP2ADDDIRTYBOX); #ifndef _IA64_
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
return; } } // Check for space
if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2ADDDIRTYBOX) > dwDP2CommandBufSize) { FlushStates(); } // Add new renderstate instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->bCommand = D3DDP2OP_ADDDIRTYBOX; bDP2CurrCmdOP = D3DDP2OP_ADDDIRTYBOX; lpDP2CurrCommand->bReserved = 0; lpDP2CurrCommand->wStateCount = 1; wDP2CurrCmdCnt = 1; #ifndef _IA64_
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
// Add adddirtybox data
LPD3DHAL_DP2ADDDIRTYBOX lpDirtyBox = (LPD3DHAL_DP2ADDDIRTYBOX)(lpDP2CurrCommand + 1); lpDirtyBox->dwSurface = dwHandle; lpDirtyBox->DirtyBox = *pBox; dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2ADDDIRTYBOX);
return; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX7::Clear"
void CD3DDDIDX7::Clear(DWORD dwFlags, DWORD clrCount, LPD3DRECT clrRects, 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) { FlushStates(); } lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->bCommand = D3DDP2OP_CLEAR; bDP2CurrCmdOP = D3DDP2OP_CLEAR; lpDP2CurrCommand->bReserved = 0; wDP2CurrCmdCnt = (WORD)clrCount; lpDP2CurrCommand->wStateCount = wDP2CurrCmdCnt; #ifndef _IA64_
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
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)); }
//-----------------------------------------------------------------------------
// This function should be called from PaletteUpdateNotify
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX7::UpdatePalette"
void CD3DDDIDX7::UpdatePalette(DWORD dwPaletteHandle, DWORD dwStartIndex, DWORD dwNumberOfIndices, PALETTEENTRY *pFirstIndex) { DWORD dwSizeChange=sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2UPDATEPALETTE) + dwNumberOfIndices*sizeof(PALETTEENTRY); if (bDP2CurrCmdOP == D3DDP2OP_UPDATEPALETTE) { // Last instruction is same, append this one to it
if (dwDP2CommandLength + dwSizeChange <= dwDP2CommandBufSize) { LPD3DHAL_DP2UPDATEPALETTE lpUpdatePal = (LPD3DHAL_DP2UPDATEPALETTE)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt; lpUpdatePal->dwPaletteHandle=dwPaletteHandle + 1; lpUpdatePal->wStartIndex=(WORD)dwStartIndex; lpUpdatePal->wNumEntries=(WORD)dwNumberOfIndices; memcpy((LPVOID)(lpUpdatePal+1),(LPVOID)pFirstIndex, dwNumberOfIndices*sizeof(PALETTEENTRY)); dwDP2CommandLength += dwSizeChange; #ifndef _IA64_
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
return; } } // Check for space
if (dwDP2CommandLength + dwSizeChange > dwDP2CommandBufSize) { FlushStates(); } // 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; #ifndef _IA64_
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
// Add texture blt data
LPD3DHAL_DP2UPDATEPALETTE lpUpdatePal = (LPD3DHAL_DP2UPDATEPALETTE)(lpDP2CurrCommand + 1); lpUpdatePal->dwPaletteHandle=dwPaletteHandle + 1; lpUpdatePal->wStartIndex=(WORD)dwStartIndex; lpUpdatePal->wNumEntries=(WORD)dwNumberOfIndices; memcpy((LPVOID)(lpUpdatePal+1),(LPVOID)pFirstIndex, dwNumberOfIndices*sizeof(PALETTEENTRY)); dwDP2CommandLength += dwSizeChange; }
//-----------------------------------------------------------------------------
// This function should be called from PaletteAssociateNotify
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX7::SetPalette"
void CD3DDDIDX7::SetPalette(DWORD dwPaletteHandle, DWORD dwPaletteFlags, CBaseTexture *pTex ) { if (pTex->IsD3DManaged()) { if (!m_pDevice->ResourceManager()->InVidmem(pTex->RMHandle())) { // We will hit this return ONLY
// when for some reason promoting
// pTex to vidmem failed.
return; } } pTex->SetPalette(dwPaletteHandle); DWORD dwSizeChange=sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2SETPALETTE); if (bDP2CurrCmdOP == D3DDP2OP_SETPALETTE) { // Last instruction is a tex blt, append this one to it
if (dwDP2CommandLength + dwSizeChange <= dwDP2CommandBufSize) { LPD3DHAL_DP2SETPALETTE lpSetPal = (LPD3DHAL_DP2SETPALETTE)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt; lpSetPal->dwPaletteHandle=dwPaletteHandle + 1; lpSetPal->dwPaletteFlags=dwPaletteFlags; lpSetPal->dwSurfaceHandle=pTex->DriverAccessibleDrawPrimHandle(); dwDP2CommandLength += dwSizeChange; #ifndef _IA64_
D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
pTex->Batch(); return; } } // Check for space
if (dwDP2CommandLength + dwSizeChange > dwDP2CommandBufSize) { FlushStates(); } // Add new renderstate instruction
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->bCommand = D3DDP2OP_SETPALETTE; bDP2CurrCmdOP = D3DDP2OP_SETPALETTE; lpDP2CurrCommand->bReserved = 0; lpDP2CurrCommand->wStateCount = 1; wDP2CurrCmdCnt = 1; #ifndef _IA64_
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
LPD3DHAL_DP2SETPALETTE lpSetPal = (LPD3DHAL_DP2SETPALETTE)(lpDP2CurrCommand + 1); lpSetPal->dwPaletteHandle=dwPaletteHandle + 1; lpSetPal->dwPaletteFlags=dwPaletteFlags; lpSetPal->dwSurfaceHandle=pTex->DriverAccessibleDrawPrimHandle(); dwDP2CommandLength += dwSizeChange;
pTex->Batch(); return; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX7::WriteStateSetToDevice"
void CD3DDDIDX7::WriteStateSetToDevice(D3DSTATEBLOCKTYPE sbt) { DWORD dwDeviceHandle; LPVOID pBuffer; DWORD dwBufferSize;
m_pDevice->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
FlushStatesCmdBufReq(dwByteCount); // Check if the driver did give us what we need or do it ourselves
GrowCommandBuffer(dwByteCount); }
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; #ifndef _IA64_
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
// Copy the entire state macro to the DP2 buffer
memcpy(pData + 1, pBuffer, dwBufferSize); if (m_ddiType < D3DDDITYPE_DX8) { // Translate buffer content to DX7 DDI
m_pDevice->m_pStateSets->TranslateDeviceBufferToDX7DDI( (DWORD*)(pData + 1), 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; #ifndef _IA64_
D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); #endif
dwDP2CommandLength += dwByteCount;
FlushStates(); }
/////////////////////////////////////////////////////////////////////////////
// //
// CD3DDDITL //
// //
/////////////////////////////////////////////////////////////////////////////
CD3DDDITL::CD3DDDITL() : CD3DDDIDX7() { m_ddiType = D3DDDITYPE_DX7TL; }
CD3DDDITL::~CD3DDDITL() { return; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDITL::SetTransform"
void CD3DDDITL::SetTransform(D3DTRANSFORMSTATETYPE state, CONST D3DMATRIX* lpMat) { // Do mapping between new world matrix states and the old ones
if ((DWORD)state >= __WORLDMATRIXBASE && (DWORD)state < (__WORLDMATRIXBASE + __MAXWORLDMATRICES)) { // World matrix is set
UINT index = (DWORD)state - __WORLDMATRIXBASE; switch (index) { case 0 : state = (D3DTRANSFORMSTATETYPE)D3DTRANSFORMSTATE_WORLD_DX7; break; case 1 : state = (D3DTRANSFORMSTATETYPE)D3DTRANSFORMSTATE_WORLD1_DX7; break; case 2 : state = (D3DTRANSFORMSTATETYPE)D3DTRANSFORMSTATE_WORLD2_DX7; break; case 3 : state = (D3DTRANSFORMSTATETYPE)D3DTRANSFORMSTATE_WORLD3_DX7; break; default : return; // State is not supported
} } // Send down the state and the matrix
LPD3DHAL_DP2SETTRANSFORM pData; pData = (LPD3DHAL_DP2SETTRANSFORM) GetHalBufferPointer(D3DDP2OP_SETTRANSFORM, sizeof(*pData)); pData->xfrmType = state; pData->matrix = *lpMat; // Update W info in case of projection matrix
if (state == D3DTRANSFORMSTATE_PROJECTION) CD3DDDIDX6::SetTransform(state, lpMat); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDITL::SetViewport"
void CD3DDDITL::SetViewport(CONST D3DVIEWPORT8* lpVwpData) { // Update viewport size
CD3DDDIDX6::SetViewport(lpVwpData);
// Update Z range
LPD3DHAL_DP2ZRANGE pData; pData = (LPD3DHAL_DP2ZRANGE)GetHalBufferPointer(D3DDP2OP_ZRANGE, sizeof(*pData)); pData->dvMinZ = lpVwpData->MinZ; pData->dvMaxZ = lpVwpData->MaxZ; } //-----------------------------------------------------------------------------
// This function is called whe software vertex processing is used
// Handle should be always legacy
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDITL::SetVertexShader"
void CD3DDDITL::SetVertexShader(DWORD dwHandle) { DXGASSERT(D3DVSD_ISLEGACY(dwHandle)); // Pre-DX8 drivers should not recieve D3DFVF_LASTBETA_UBYTE4 bit
m_CurrentVertexShader = dwHandle & ~D3DFVF_LASTBETA_UBYTE4; #if DBG
m_VertexSizeFromShader = ComputeVertexSizeFVF(dwHandle); #endif
} //-----------------------------------------------------------------------------
// This function is called whe hardware vertex processing is used
// Redundant shader check has been done at the API level
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDITL::SetVertexShaderHW"
void CD3DDDITL::SetVertexShaderHW(DWORD dwHandle) { if( D3DVSD_ISLEGACY(dwHandle) ) { // Pre-DX8 drivers should not recieve D3DFVF_LASTBETA_UBYTE4 bit
m_CurrentVertexShader = dwHandle & ~D3DFVF_LASTBETA_UBYTE4; } else { CVShader* pShader = (CVShader*)m_pDevice->m_pVShaderArray->GetObject(dwHandle); if( pShader == NULL ) { D3D_THROW( D3DERR_INVALIDCALL, "Bad handle passed to SetVertexShader DDI" ) } if( pShader->m_Declaration.m_bLegacyFVF == FALSE ) { D3D_THROW( D3DERR_INVALIDCALL, "Declaration is too complex for " "the Driver to handle." ); } else { m_CurrentVertexShader = pShader->m_Declaration.m_dwInputFVF; } } #if DBG
m_VertexSizeFromShader = ComputeVertexSizeFVF(m_CurrentVertexShader); #endif
} //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDITL::SetMaterial"
void CD3DDDITL::SetMaterial(CONST D3DMATERIAL8* pMat) { LPD3DHAL_DP2SETMATERIAL pData; pData = (LPD3DHAL_DP2SETMATERIAL)GetHalBufferPointer(D3DDP2OP_SETMATERIAL, sizeof(*pData)); *pData = *((LPD3DHAL_DP2SETMATERIAL)pMat); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDITL::SetLight"
void CD3DDDITL::SetLight(DWORD dwLightIndex, CONST D3DLIGHT8* pLight) { LPD3DHAL_DP2SETLIGHT pData; pData = (LPD3DHAL_DP2SETLIGHT) GetHalBufferPointer(D3DDP2OP_SETLIGHT, sizeof(*pData) + sizeof(D3DLIGHT8)); pData->dwIndex = dwLightIndex; pData->dwDataType = D3DHAL_SETLIGHT_DATA; D3DLIGHT8* p = (D3DLIGHT8*)((LPBYTE)pData + sizeof(D3DHAL_DP2SETLIGHT)); *p = *pLight; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDITL::CreateLight"
void CD3DDDITL::CreateLight(DWORD dwLightIndex) { LPD3DHAL_DP2CREATELIGHT pData; pData = (LPD3DHAL_DP2CREATELIGHT)GetHalBufferPointer(D3DDP2OP_CREATELIGHT, sizeof(*pData)); pData->dwIndex = dwLightIndex; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDITL::LightEnable"
void CD3DDDITL::LightEnable(DWORD dwLightIndex, BOOL bEnable) { 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 "CD3DDDITL::SetClipPlane"
void CD3DDDITL::SetClipPlane(DWORD dwPlaneIndex, CONST D3DVALUE* pPlaneEquation) { 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 "CD3DDDITL::CreateVertexShader"
void CD3DDDITL::CreateVertexShader(CONST DWORD* pdwDeclaration, DWORD dwDeclarationSize, CONST DWORD* pdwFunction, DWORD dwFunctionSize, DWORD dwHandle, BOOL bLegacyFVF) { if( bLegacyFVF == FALSE ) { D3D_THROW(D3DERR_INVALIDCALL, "The declaration is too complex for the driver to handle"); } } //-----------------------------------------------------------------------------
// Allocates space for the internal clip buffer and sets lpClipFlags pointer
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::PrepareForClipping"
void CD3DDDIDX6::PrepareForClipping(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice);
if (!(pv->dwDeviceFlags & D3DDEV_VBPROCVER)) { // Grow clip flags buffer if we need clipping
DWORD size = pv->dwNumVertices * sizeof(D3DFE_CLIPCODE); if (size > pDevice->HVbuf.GetSize()) { if (pDevice->HVbuf.Grow(size) != D3D_OK) { D3D_THROW(E_OUTOFMEMORY, "Could not grow clip buffer" ); } } pv->lpClipFlags = (D3DFE_CLIPCODE*)pDevice->HVbuf.GetAddress(); } else { // For vertex buffers, which are destination for ProcessVertices
// clip buffer is already computed
pv->lpClipFlags = pDevice->m_pStream[0].m_pVB->GetClipCodes(); #if DBG
if (pv->lpClipFlags == NULL) { D3D_THROW_FAIL("Clip codes are not computed for the vertex buffer"); } #endif
pv->dwClipUnion = 0xFFFFFFFF; // Force clipping
pv->lpClipFlags += StartVertex; } } //-----------------------------------------------------------------------------
// Point sprites are drawn as indexed triangle list
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::StartPointSprites"
void CD3DDDIDX6::StartPointSprites() { D3DFE_PROCESSVERTICES* pv = static_cast<CD3DHal*>(m_pDevice)->m_pv; if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { m_pDevice->UpdateTextures(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } // Reserve place for the output vertices
const UINT size = NUM_SPRITES_IN_BATCH * 4 * m_dwOutputSizePS;
// We may have a different vertex type for point sprites
DWORD tmpFVF = pv->dwVIDOut; pv->dwVIDOut = m_dwVIDOutPS;
// For StartPrimTL we should use vertex size, which will go to the driver
DWORD tmpVertexSize = pv->dwOutputSize; pv->dwOutputSize = m_dwOutputSizePS;
m_pCurSpriteVertex = (BYTE*)StartPrimTL(pv, size, TRUE);
// Restore vertex size, which is size before point sprite emulation
pv->dwOutputSize = tmpVertexSize;
// Vertex base and vertex count could be changed during clipping
// So we save them here and use in the EndPointSprites
m_dwVertexBasePS = this->dwVertexBase; m_dwVertexCountPS = this->dwDP2VertexCount;
// Continue processing with the original FVF
pv->dwVIDOut = tmpFVF; // Reserve place for indices
UINT count = NUM_SPRITES_IN_BATCH * 2 * 6;
// We change lpDP2CurrCommand here, so to prevent combining multiple driver
// calls to one token in case when all points are off screen, we clear
// bDP2CurrCmdOP.
bDP2CurrCmdOP = 0;
lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)ReserveSpaceInCommandBuffer(count); m_pCurPointSpriteIndex = (WORD*)((BYTE*)(lpDP2CurrCommand + 1) + sizeof(D3DHAL_DP2STARTVERTEX)); m_CurNumberOfSprites = 0; ((LPD3DHAL_DP2STARTVERTEX)(lpDP2CurrCommand+1))->wVStart = (WORD)this->dwVertexBase;
SetWithinPrimitive(TRUE); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::NextSprite"
void CD3DDDIDX6::NextSprite(float x, float y, float z, float w, DWORD diffuse, DWORD specular, float* pTexture, UINT TextureSize, float PointSize) { D3DFE_PROCESSVERTICES* pv = static_cast<CD3DHal*>(m_pDevice)->m_pv;
BOOL bTexGen = pv->lpdwRStates[D3DRS_POINTSPRITEENABLE] != 0;
if (m_CurNumberOfSprites >= NUM_SPRITES_IN_BATCH) { EndPointSprites(); StartPointSprites(); } // Compute point size
PointSize = PointSize * 0.5f;
// Build sprite vertices
BYTE* v1 = m_pCurSpriteVertex; BYTE* v2 = m_pCurSpriteVertex + m_dwOutputSizePS; BYTE* v3 = m_pCurSpriteVertex + m_dwOutputSizePS * 2; BYTE* v4 = m_pCurSpriteVertex + m_dwOutputSizePS * 3; float x1, y1, x2, y2, x3, y3, x4, y4; x1 = x - PointSize; y1 = y - PointSize; x2 = x + PointSize; y2 = y + PointSize; float tx1 = 0; // Interpolation coefficient at left plane
float tx2 = 1; // Interpolation coefficient at right plane
float ty1 = 0; // Interpolation coefficient at top plane
float ty2 = 1; // Interpolation coefficient at bottom plane
if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP) { ((D3DVECTORH*)v1)->x = x1; ((D3DVECTORH*)v1)->y = y1; ((D3DVECTORH*)v1)->z = z; ((D3DVECTORH*)v1)->w = w; ((D3DVECTORH*)v2)->x = x2; ((D3DVECTORH*)v2)->y = y1; ((D3DVECTORH*)v2)->z = z; ((D3DVECTORH*)v2)->w = w; ((D3DVECTORH*)v3)->x = x2; ((D3DVECTORH*)v3)->y = y2; ((D3DVECTORH*)v3)->z = z; ((D3DVECTORH*)v3)->w = w; ((D3DVECTORH*)v4)->x = x1; ((D3DVECTORH*)v4)->y = y2; ((D3DVECTORH*)v4)->z = z; ((D3DVECTORH*)v4)->w = w; } else {// Do clipping
// new x and y
float xnew1 = x1, xnew2 = x2; float ynew1 = y1, ynew2 = y2; if (x1 < pv->vcache.minX) if (x2 < pv->vcache.minX) return; else { xnew1 = pv->vcache.minX; if (bTexGen) tx1 = (xnew1 - x1) / (x2 - x1); } else if (x2 > pv->vcache.maxX) if (x1 > pv->vcache.maxX) return; else { xnew2 = pv->vcache.maxX; if (bTexGen) tx2 = (xnew2 - x1) / (x2 - x1); } if (y1 < pv->vcache.minY) if (y2 < pv->vcache.minY) return; else { ynew1 = pv->vcache.minY; if (bTexGen) ty1 = (ynew1 - y1) / (y2 - y1); } else if (y2 > pv->vcache.maxY) if (y1 > pv->vcache.maxY) return; else { ynew2 = pv->vcache.maxY; if (bTexGen) ty2 = (ynew2 - y1) / (y2 - y1); } ((D3DVECTORH*)v1)->x = xnew1; ((D3DVECTORH*)v1)->y = ynew1; ((D3DVECTORH*)v1)->z = z; ((D3DVECTORH*)v1)->w = w; ((D3DVECTORH*)v2)->x = xnew2; ((D3DVECTORH*)v2)->y = ynew1; ((D3DVECTORH*)v2)->z = z; ((D3DVECTORH*)v2)->w = w; ((D3DVECTORH*)v3)->x = xnew2; ((D3DVECTORH*)v3)->y = ynew2; ((D3DVECTORH*)v3)->z = z; ((D3DVECTORH*)v3)->w = w; ((D3DVECTORH*)v4)->x = xnew1; ((D3DVECTORH*)v4)->y = ynew2; ((D3DVECTORH*)v4)->z = z; ((D3DVECTORH*)v4)->w = w; } UINT offset = 4*4; if (m_dwVIDOutPS & D3DFVF_DIFFUSE) { *(DWORD*)(v1 + offset) = diffuse; *(DWORD*)(v2 + offset) = diffuse; *(DWORD*)(v3 + offset) = diffuse; *(DWORD*)(v4 + offset) = diffuse; offset += 4; } if (m_dwVIDOutPS & D3DFVF_SPECULAR) { *(DWORD*)(v1 + offset) = specular; *(DWORD*)(v2 + offset) = specular; *(DWORD*)(v3 + offset) = specular; *(DWORD*)(v4 + offset) = specular; offset += 4; } if (bTexGen) { ((float*)(v1 + offset))[0] = tx1; ((float*)(v1 + offset))[1] = ty1; ((float*)(v2 + offset))[0] = tx2; ((float*)(v2 + offset))[1] = ty1; ((float*)(v3 + offset))[0] = tx2; ((float*)(v3 + offset))[1] = ty2; ((float*)(v4 + offset))[0] = tx1; ((float*)(v4 + offset))[1] = ty2; } else { // Copy input texture coordinates
memcpy(v1 + offset, pTexture, TextureSize); memcpy(v2 + offset, pTexture, TextureSize); memcpy(v3 + offset, pTexture, TextureSize); memcpy(v4 + offset, pTexture, TextureSize); } m_pCurSpriteVertex = v4 + m_dwOutputSizePS;
// Output indices for 2 triangles
WORD index = m_CurNumberOfSprites << 2; m_pCurPointSpriteIndex[0] = index; m_pCurPointSpriteIndex[1] = index + 1; m_pCurPointSpriteIndex[2] = index + 2; m_pCurPointSpriteIndex[3] = index; m_pCurPointSpriteIndex[4] = index + 2; m_pCurPointSpriteIndex[5] = index + 3; m_pCurPointSpriteIndex += 6;
m_CurNumberOfSprites++; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::EndPointSprites"
void CD3DDDIDX6::EndPointSprites() { if (m_CurNumberOfSprites) { dwDP2CommandLength += (DWORD) ((BYTE*)this->m_pCurPointSpriteIndex - (BYTE*)this->lpDP2CurrCommand); this->lpDP2CurrCommand->bCommand = D3DDP2OP_INDEXEDTRIANGLELIST2; this->bDP2CurrCmdOP = D3DDP2OP_INDEXEDTRIANGLELIST2; this->lpDP2CurrCommand->bReserved = 0; this->lpDP2CurrCommand->wPrimitiveCount = m_CurNumberOfSprites * 2; #if DBG
if (m_bValidateCommands) ValidateCommand(this->lpDP2CurrCommand); #endif
UINT vertexCount = m_CurNumberOfSprites << 2; this->dwVertexBase = m_dwVertexBasePS + vertexCount; this->dwDP2VertexCount = m_dwVertexCountPS + vertexCount; EndPrim(m_dwOutputSizePS); m_CurNumberOfSprites = 0; } else { // We need to restore dwVertexBase and dwDP2VertexCount, because
// they could be changed during clipping of transformed vertices.
// But they should reflect position in TL buffer, not in user buffer
this->dwVertexBase = m_dwVertexBasePS; this->dwDP2VertexCount = m_dwVertexCountPS; EndPrim(m_dwOutputSizePS); } SetWithinPrimitive(FALSE); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::UpdatePalette"
void CD3DDDIDX6::UpdatePalette(DWORD dwPaletteHandle, DWORD dwStartIndex, DWORD dwNumberOfIndices, PALETTEENTRY *pFirstIndex) { D3D8_UPDATEPALETTEDATA Data; Data.hDD = m_pDevice->GetHandle(); Data.Palette = dwPaletteHandle; Data.ColorTable = pFirstIndex; Data.ddRVal = S_OK; HRESULT ret = m_pDevice->GetHalCallbacks()->UpdatePalette(&Data); if (ret != DDHAL_DRIVER_HANDLED || Data.ddRVal != S_OK) { D3D_ERR( "Driver failed UpdatePalette call" ); throw D3DERR_INVALIDCALL; } } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::SetPalette"
void CD3DDDIDX6::SetPalette(DWORD dwPaletteHandle, DWORD dwPaletteFlags, CBaseTexture *pTex) { if (pTex->IsD3DManaged()) { if (!m_pDevice->ResourceManager()->InVidmem(pTex->RMHandle())) { // We will hit this return ONLY
// when for some reason promoting
// pTex to vidmem failed.
return; } } D3D8_SETPALETTEDATA Data; Data.hDD = m_pDevice->GetHandle(); Data.hSurface = pTex->DriverAccessibleKernelHandle(); Data.Palette = dwPaletteHandle; Data.ddRVal = S_OK; HRESULT ret = m_pDevice->GetHalCallbacks()->SetPalette(&Data); if (ret != DDHAL_DRIVER_HANDLED || Data.ddRVal != S_OK) { D3D_ERR( "Driver failed SetPalette call" ); throw D3DERR_INVALIDCALL; } pTex->SetPalette(dwPaletteHandle); } //-----------------------------------------------------------------------------
#if DBG
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::ValidateVertex"
void CD3DDDIDX6::ValidateVertex(LPDWORD lpdwVertex) { D3DFE_PROCESSVERTICES* pv = static_cast<CD3DHal*>(m_pDevice)->m_pv; DWORD dwFVF = pv->dwVIDOut; CD3DHal* pDevice = static_cast<CD3DHal*>(m_pDevice); if (FVF_TRANSFORMED(dwFVF)) { float left, right, top, bottom; if (pv->dwDeviceFlags & D3DDEV_GUARDBAND) { left = pv->vcache.minXgb; right = pv->vcache.maxXgb; top = pv->vcache.minYgb; bottom = pv->vcache.maxYgb; } else { left = (float)pDevice->m_Viewport.X; top = (float)pDevice->m_Viewport.Y; right = (float)pDevice->m_Viewport.X + pDevice->m_Viewport.Width; bottom = (float)pDevice->m_Viewport.Y + pDevice->m_Viewport.Height; } float x = ((float*)lpdwVertex)[0]; float y = ((float*)lpdwVertex)[1]; float z = ((float*)lpdwVertex)[2]; float w = ((float*)lpdwVertex)[3];
if (x < left || x > right) { D3D_THROW_FAIL("X coordinate out of range!"); }
if (y < top || y > bottom) { D3D_THROW_FAIL("Y coordinate out of range!"); }
if (pv->lpdwRStates[D3DRS_ZENABLE] || pv->lpdwRStates[D3DRS_ZWRITEENABLE]) { // Allow a little slack for those generating triangles exactly on the
// depth limit. Needed for Quake.
if (z < -0.00015f || z > 1.00015f) { D3D_THROW_FAIL("Z coordinate out of range!"); } } UINT index = 4;
if (dwFVF & D3DFVF_DIFFUSE) index++;
if (dwFVF & D3DFVF_SPECULAR) index++;
UINT nTex = FVF_TEXCOORD_NUMBER(dwFVF); if (nTex > 0) { if (w <= 0 ) { D3D_THROW_FAIL("RHW out of range!"); } for (UINT i=0; i < nTex; i++) { float u = ((float*)lpdwVertex)[index]; float v = ((float*)lpdwVertex)[index+1]; if (u < -100 || u > 100 || v < -100 || v > 100) { D3D_THROW_FAIL("Texture coordinate out of range!"); } index += 2; } } } } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DDDIDX6::ValidateCommand"
void CD3DDDIDX6::ValidateCommand(LPD3DHAL_DP2COMMAND lpCmd) { D3DFE_PROCESSVERTICES* pv = static_cast<CD3DHal*>(m_pDevice)->m_pv;
BYTE* pVertices; if (dp2data.dwFlags & D3DHALDP2_USERMEMVERTICES) pVertices = (LPBYTE)(dp2data.lpVertices); else if (!lpDP2CurrBatchVBI->IsLocked()) { lpDP2CurrBatchVBI->Lock(dp2data.dwVertexOffset, this->dwDP2VertexCount, &pVertices, DDLOCK_READONLY); } else { pVertices = lpDP2CurrBatchVBI->Data(); }
DWORD dwVertexSize = pv->dwOutputSize; WORD wStart, wCount; switch (lpCmd->bCommand) { case D3DDP2OP_TRIANGLELIST: { LPD3DHAL_DP2TRIANGLELIST pTri = (LPD3DHAL_DP2TRIANGLELIST)(lpCmd + 1); wStart = pTri->wVStart; wCount =lpCmd->wPrimitiveCount * 3; } break; case D3DDP2OP_TRIANGLESTRIP: case D3DDP2OP_TRIANGLEFAN: { LPD3DHAL_DP2TRIANGLEFAN pFan = (LPD3DHAL_DP2TRIANGLEFAN)(lpCmd + 1); wStart = pFan->wVStart; wCount = lpCmd->wPrimitiveCount + 2; } break; case D3DDP2OP_TRIANGLEFAN_IMM: { wCount = lpCmd->wPrimitiveCount + 2; BYTE* pVertices = (BYTE*)(lpCmd + 1) + sizeof(D3DHAL_DP2TRIANGLEFAN_IMM); pVertices = (BYTE*)(((ULONG_PTR)pVertices + 3) & ~3); for (WORD i=0; i < wCount; ++i) { ValidateVertex((DWORD*)(pVertices + i * dwVertexSize)); } goto l_exit; } case D3DDP2OP_INDEXEDTRIANGLELIST2: { wCount = lpCmd->wPrimitiveCount * 3; LPD3DHAL_DP2STARTVERTEX lpStartVertex = (LPD3DHAL_DP2STARTVERTEX)(lpCmd + 1); WORD* pIndices = (WORD*)(lpStartVertex + 1); wStart = lpStartVertex->wVStart; pVertices += wStart * dwVertexSize; DWORD dwNumVertices = this->dwDP2VertexCount - wStart; for (WORD i = 0; i < wCount; ++i) { if (pIndices[i] >= dwNumVertices) { D3D_THROW_FAIL("Invalid index in ValidateCommand"); } ValidateVertex((LPDWORD)(pVertices + pIndices[i] * dwVertexSize)); } } goto l_exit; // Fall through
default: goto l_exit; }
{ for (WORD i = wStart; i < wStart + wCount; ++i) { ValidateVertex((LPDWORD)(pVertices + i * dwVertexSize)); } } l_exit: if (!(dp2data.dwFlags & D3DHALDP2_USERMEMVERTICES)) lpDP2CurrBatchVBI->Unlock(); } //-----------------------------------------------------------------------------
// This function could be used to go through all commands in the command buffer
// and find failed command at a particular offset
//
#undef DPF_MODNAME
#define DPF_MODNAME "ValidateCommandBuffer"
HRESULT ValidateCommandBuffer(LPBYTE pBuffer, DWORD dwCommandLength, DWORD dwStride) { LPD3DHAL_DP2COMMAND pCmd = (LPD3DHAL_DP2COMMAND)pBuffer; LPBYTE CmdEnd = pBuffer + dwCommandLength; loop: UINT CommandOffset = (UINT)((LPBYTE)pCmd - pBuffer); switch(pCmd->bCommand) { case D3DDP2OP_STATESET: { LPD3DHAL_DP2STATESET pStateSetOp = (LPD3DHAL_DP2STATESET)(pCmd + 1);
switch (pStateSetOp->dwOperation) { case D3DHAL_STATESETBEGIN : break; case D3DHAL_STATESETEND : break; case D3DHAL_STATESETDELETE : break; case D3DHAL_STATESETEXECUTE: break; case D3DHAL_STATESETCAPTURE: break; case D3DHAL_STATESETCREATE: break; default : return DDERR_INVALIDPARAMS; } pCmd = (LPD3DHAL_DP2COMMAND)(pStateSetOp + pCmd->wStateCount); } break; case D3DDP2OP_VIEWPORTINFO: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2VIEWPORTINFO *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_WINFO: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2WINFO *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_RENDERSTATE: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2RENDERSTATE *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_TEXTURESTAGESTATE: { pCmd = (LPD3DHAL_DP2COMMAND) ((LPD3DHAL_DP2TEXTURESTAGESTATE)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_INDEXEDTRIANGLELIST: { WORD cPrims = pCmd->wPrimitiveCount; pCmd = (LPD3DHAL_DP2COMMAND)((PUINT8)(pCmd + 1) + sizeof(D3DHAL_DP2INDEXEDTRIANGLELIST) * cPrims); } break; case D3DDP2OP_INDEXEDLINELIST: { // Update the command buffer pointer
pCmd = (LPD3DHAL_DP2COMMAND)((PUINT8)(pCmd + 1) + pCmd->wPrimitiveCount * sizeof(D3DHAL_DP2INDEXEDLINELIST)); } break; case D3DDP2OP_POINTS: { D3DHAL_DP2POINTS *pPt = (D3DHAL_DP2POINTS *)(pCmd + 1); pPt += pCmd->wPrimitiveCount; pCmd = (LPD3DHAL_DP2COMMAND)pPt; } break; case D3DDP2OP_LINELIST: { D3DHAL_DP2LINELIST *pLine = (D3DHAL_DP2LINELIST *)(pCmd + 1); pCmd = (LPD3DHAL_DP2COMMAND)(pLine + 1); } break; case D3DDP2OP_INDEXEDLINELIST2: { LPD3DHAL_DP2STARTVERTEX lpStartVertex = (LPD3DHAL_DP2STARTVERTEX)(pCmd + 1);
pCmd = (LPD3DHAL_DP2COMMAND)((PUINT8)(lpStartVertex + 1) + pCmd->wPrimitiveCount * sizeof(D3DHAL_DP2INDEXEDLINELIST)); } break; case D3DDP2OP_LINESTRIP: { D3DHAL_DP2LINESTRIP *pLine = (D3DHAL_DP2LINESTRIP *)(pCmd + 1); pCmd = (LPD3DHAL_DP2COMMAND)(pLine + 1); } break; case D3DDP2OP_INDEXEDLINESTRIP: { DWORD dwNumIndices = pCmd->wPrimitiveCount + 1; LPD3DHAL_DP2STARTVERTEX lpStartVertex = (LPD3DHAL_DP2STARTVERTEX)(pCmd + 1); pCmd = (LPD3DHAL_DP2COMMAND)((PUINT8)(lpStartVertex + 1) + dwNumIndices * sizeof(WORD)); } break; case D3DDP2OP_TRIANGLELIST: { D3DHAL_DP2TRIANGLELIST *pTri = (D3DHAL_DP2TRIANGLELIST *)(pCmd + 1); pCmd = (LPD3DHAL_DP2COMMAND)(pTri + 1); } break; case D3DDP2OP_INDEXEDTRIANGLELIST2: { DWORD dwNumIndices = pCmd->wPrimitiveCount*3; LPD3DHAL_DP2STARTVERTEX lpStartVertex = (LPD3DHAL_DP2STARTVERTEX)(pCmd + 1); pCmd = (LPD3DHAL_DP2COMMAND)((PUINT8)(lpStartVertex + 1) + dwNumIndices * sizeof(WORD)); } break; case D3DDP2OP_TRIANGLESTRIP: { D3DHAL_DP2TRIANGLESTRIP *pTri = (D3DHAL_DP2TRIANGLESTRIP *)(pCmd + 1); pCmd = (LPD3DHAL_DP2COMMAND)(pTri + 1); } break; case D3DDP2OP_INDEXEDTRIANGLESTRIP: { DWORD dwNumIndices = pCmd->wPrimitiveCount+2; LPD3DHAL_DP2STARTVERTEX lpStartVertex = (LPD3DHAL_DP2STARTVERTEX)(pCmd + 1); pCmd = (LPD3DHAL_DP2COMMAND)((PUINT8)(lpStartVertex + 1) + dwNumIndices * sizeof(WORD)); } break; case D3DDP2OP_TRIANGLEFAN: { D3DHAL_DP2TRIANGLEFAN *pTri = (D3DHAL_DP2TRIANGLEFAN *)(pCmd + 1); pCmd = (LPD3DHAL_DP2COMMAND)(pTri + 1); } break; case D3DDP2OP_INDEXEDTRIANGLEFAN: { DWORD dwNumIndices = pCmd->wPrimitiveCount + 2; LPD3DHAL_DP2STARTVERTEX lpStartVertex = (LPD3DHAL_DP2STARTVERTEX)(pCmd + 1); pCmd = (LPD3DHAL_DP2COMMAND)((PUINT8)(lpStartVertex + 1) + dwNumIndices * sizeof(WORD)); } break; case D3DDP2OP_TRIANGLEFAN_IMM: { DWORD vertexCount = pCmd->wPrimitiveCount + 2; // Make sure the pFanVtx pointer is DWORD aligned: (pFanVtx +3) % 4
PUINT8 pFanVtx = (PUINT8) (((ULONG_PTR)(pCmd + 1) + sizeof(D3DHAL_DP2TRIANGLEFAN_IMM) + 3) & ~3);
pCmd = (LPD3DHAL_DP2COMMAND)((PUINT8)pFanVtx + vertexCount * dwStride); } break; case D3DDP2OP_LINELIST_IMM: { DWORD vertexCount = pCmd->wPrimitiveCount * 2; // Make sure the pLineVtx pointer is DWORD aligned:
// (pLineVtx +3) % 4
PUINT8 pLineVtx = (PUINT8)(((ULONG_PTR)(pCmd + 1) + 3) & ~3); pCmd = (LPD3DHAL_DP2COMMAND)((PUINT8)pLineVtx + vertexCount * dwStride); } break; case D3DDP2OP_DRAWPRIMITIVE: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2DRAWPRIMITIVE *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_DRAWPRIMITIVE2: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2DRAWPRIMITIVE2 *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_DRAWRECTPATCH: { LPD3DHAL_DP2DRAWRECTPATCH pDP = (LPD3DHAL_DP2DRAWRECTPATCH)(pCmd + 1); for( int i = 0; i < pCmd->wStateCount; i++ ) { bool hassegs = (pDP->Flags & RTPATCHFLAG_HASSEGS) != 0; bool hasinfo = (pDP->Flags & RTPATCHFLAG_HASINFO) != 0; if(hassegs) { pDP = (LPD3DHAL_DP2DRAWRECTPATCH)((BYTE*)(pDP + 1) + sizeof(FLOAT) * 4); } else { ++pDP; } if(hasinfo) { pDP = (LPD3DHAL_DP2DRAWRECTPATCH)((BYTE*)pDP + sizeof(D3DRECTPATCH_INFO)); } } pCmd = (LPD3DHAL_DP2COMMAND)pDP; } break; case D3DDP2OP_DRAWTRIPATCH: { LPD3DHAL_DP2DRAWTRIPATCH pDP = (LPD3DHAL_DP2DRAWTRIPATCH)(pCmd + 1); for( int i = 0; i < pCmd->wStateCount; i++ ) { bool hassegs = (pDP->Flags & RTPATCHFLAG_HASSEGS) != 0; bool hasinfo = (pDP->Flags & RTPATCHFLAG_HASINFO) != 0; if(hassegs) { pDP = (LPD3DHAL_DP2DRAWTRIPATCH)((BYTE*)(pDP + 1) + sizeof(FLOAT) * 3); } else { ++pDP; } if(hasinfo) { pDP = (LPD3DHAL_DP2DRAWTRIPATCH)((BYTE*)pDP + sizeof(D3DTRIPATCH_INFO)); } } pCmd = (LPD3DHAL_DP2COMMAND)pDP; } break; case D3DDP2OP_DRAWINDEXEDPRIMITIVE: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2DRAWINDEXEDPRIMITIVE *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_DRAWINDEXEDPRIMITIVE2: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2DRAWINDEXEDPRIMITIVE2 *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_CLIPPEDTRIANGLEFAN: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_CLIPPEDTRIANGLEFAN*)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_ZRANGE: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2ZRANGE *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_SETMATERIAL: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2SETMATERIAL *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_SETLIGHT: { pCmd = (LPD3DHAL_DP2COMMAND)((LPBYTE)(pCmd + 1) + sizeof(D3DHAL_DP2SETLIGHT)); } break; case D3DDP2OP_CREATELIGHT: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2CREATELIGHT *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_SETTRANSFORM: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2SETTRANSFORM *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_MULTIPLYTRANSFORM: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2MULTIPLYTRANSFORM *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_EXT: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2EXT *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_SETRENDERTARGET: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2SETRENDERTARGET*)(pCmd + 1) + pCmd->wStateCount); } break; case D3DDP2OP_CLEAR: { pCmd = (LPD3DHAL_DP2COMMAND)((LPBYTE)(pCmd + 1) + sizeof(D3DHAL_DP2CLEAR) + (pCmd->wStateCount - 1) * sizeof(RECT)); } break; case D3DDP2OP_SETCLIPPLANE: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2SETCLIPPLANE *)(pCmd + 1) + pCmd->wStateCount); } break; case D3DOP_SPAN: // Skip over
pCmd = (LPD3DHAL_DP2COMMAND)((LPBYTE)(pCmd + 1) + pCmd->wPrimitiveCount * pCmd->bReserved ); break; case D3DDP2OP_CREATEVERTEXSHADER: { LPD3DHAL_DP2CREATEVERTEXSHADER pCVS = (LPD3DHAL_DP2CREATEVERTEXSHADER)(pCmd + 1); WORD i;
for( i = 0; i < pCmd->wStateCount ; i++ ) { LPDWORD pDecl = (LPDWORD)(pCVS + 1); LPDWORD pCode = (LPDWORD)((LPBYTE)pDecl + pCVS->dwDeclSize); pCVS = (LPD3DHAL_DP2CREATEVERTEXSHADER)((LPBYTE)pCode + pCVS->dwCodeSize); } pCmd = (LPD3DHAL_DP2COMMAND)pCVS; break; } case D3DDP2OP_DELETEVERTEXSHADER: pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2VERTEXSHADER *)(pCmd + 1) + pCmd->wStateCount); break; case D3DDP2OP_SETVERTEXSHADER: pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2VERTEXSHADER *)(pCmd + 1) + pCmd->wStateCount); break; case D3DDP2OP_SETVERTEXSHADERCONST: { LPD3DHAL_DP2SETVERTEXSHADERCONST pSVC = (LPD3DHAL_DP2SETVERTEXSHADERCONST)(pCmd + 1); WORD i; for( i = 0; i < pCmd->wStateCount ; i++ ) { LPDWORD pData = (LPDWORD)(pSVC + 1); pSVC = (LPD3DHAL_DP2SETVERTEXSHADERCONST)((LPBYTE)pData + pSVC->dwCount * 4 * sizeof( float ) ); } pCmd = (LPD3DHAL_DP2COMMAND)pSVC; break; } case D3DDP2OP_SETSTREAMSOURCE: pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2SETSTREAMSOURCE *)(pCmd + 1) + pCmd->wStateCount); break; case D3DDP2OP_SETSTREAMSOURCEUM: pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2SETSTREAMSOURCEUM *)(pCmd + 1) + pCmd->wStateCount); break; case D3DDP2OP_SETINDICES: pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2SETINDICES *)(pCmd + 1) + pCmd->wStateCount); break; case D3DDP2OP_CREATEPIXELSHADER: { LPD3DHAL_DP2CREATEPIXELSHADER pCPS = (LPD3DHAL_DP2CREATEPIXELSHADER)(pCmd + 1); WORD i;
for( i = 0; i < pCmd->wStateCount ; i++ ) { LPDWORD pCode = (LPDWORD)(pCPS + 1); pCPS = (LPD3DHAL_DP2CREATEPIXELSHADER)((LPBYTE)pCode + pCPS->dwCodeSize); } pCmd = (LPD3DHAL_DP2COMMAND)pCPS; break; } case D3DDP2OP_DELETEPIXELSHADER: pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2PIXELSHADER *)(pCmd + 1) + pCmd->wStateCount); break; case D3DDP2OP_SETPIXELSHADER: pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2PIXELSHADER *)(pCmd + 1) + pCmd->wStateCount); break; case D3DDP2OP_SETPIXELSHADERCONST: { LPD3DHAL_DP2SETPIXELSHADERCONST pSVC = (LPD3DHAL_DP2SETPIXELSHADERCONST)(pCmd + 1); WORD i; for( i = 0; i < pCmd->wStateCount ; i++ ) { LPDWORD pData = (LPDWORD)(pSVC + 1); pSVC = (LPD3DHAL_DP2SETPIXELSHADERCONST)((LPBYTE)pData + pSVC->dwCount * 4 * sizeof( float ) ); } pCmd = (LPD3DHAL_DP2COMMAND)pSVC; break; } case D3DDP2OP_SETPALETTE: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2SETPALETTE *)(pCmd + 1) + pCmd->wStateCount); break; } case D3DDP2OP_UPDATEPALETTE: { LPD3DHAL_DP2UPDATEPALETTE pUP = (LPD3DHAL_DP2UPDATEPALETTE)(pCmd + 1); WORD i; for( i = 0; i < pCmd->wStateCount ; i++ ) { PALETTEENTRY* pEntries = (PALETTEENTRY *)(pUP + 1); pUP = (LPD3DHAL_DP2UPDATEPALETTE)(pEntries + pUP->wNumEntries); } pCmd = (LPD3DHAL_DP2COMMAND)pUP; break; } case D3DDP2OP_SETTEXLOD: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2SETTEXLOD *)(pCmd + 1) + pCmd->wStateCount); break; } case D3DDP2OP_SETPRIORITY: { pCmd = (LPD3DHAL_DP2COMMAND) ((D3DHAL_DP2SETPRIORITY *)(pCmd + 1) + pCmd->wStateCount); break; } case D3DDP2OP_TEXBLT: { LPD3DHAL_DP2TEXBLT pTB = (LPD3DHAL_DP2TEXBLT)(pCmd + 1); for( WORD i = 0; i < pCmd->wStateCount ; i++ ) { pTB++; } pCmd = (LPD3DHAL_DP2COMMAND)pTB; break; } case D3DDP2OP_BUFFERBLT: { LPD3DHAL_DP2BUFFERBLT pBB = (LPD3DHAL_DP2BUFFERBLT)(pCmd + 1); for( WORD i = 0; i < pCmd->wStateCount ; i++ ) { pBB++; } pCmd = (LPD3DHAL_DP2COMMAND)pBB; break; } case D3DDP2OP_VOLUMEBLT: { LPD3DHAL_DP2VOLUMEBLT pVB = (LPD3DHAL_DP2VOLUMEBLT)(pCmd + 1); for( WORD i = 0; i < pCmd->wStateCount ; i++ ) { pVB++; } pCmd = (LPD3DHAL_DP2COMMAND)pVB; break; } case D3DOP_MATRIXLOAD: case D3DOP_MATRIXMULTIPLY: case D3DOP_STATETRANSFORM: case D3DOP_STATELIGHT: case D3DOP_TEXTURELOAD: case D3DOP_BRANCHFORWARD: case D3DOP_SETSTATUS: case D3DOP_EXIT: case D3DOP_PROCESSVERTICES: { D3D_ERR( "Command is not supported\n" ); return E_FAIL; break; } default: D3D_ERR( "Unknown command encountered" ); return E_FAIL; } if ((LPBYTE)pCmd < CmdEnd) goto loop;
return S_OK; }
#endif // DBG
|