#include "pch.cpp" #pragma hdrstop /*==========================================================================; * * Copyright (C) 2000 Microsoft Corporation. All Rights Reserved. * * File: ddidx8.cpp * Content: Direct3D Dx8 DDI encapsulation implementations * ***************************************************************************/ #include "d3d8p.h" #include "ddi.h" #include "fe.h" #include "ddi.inl" extern DWORD g_DebugFlags; extern HRESULT ProcessClippedPointSprites(D3DFE_PROCESSVERTICES *pv); extern DWORD D3DFE_GenClipFlags(D3DFE_PROCESSVERTICES *pv); //----------------------------------------------------------------------------- // TL stream which is read-only // class CTLStreamRO: public CTLStream { public: CTLStreamRO(): CTLStream(TRUE) {m_dwIndex = 0; m_bUserMemStream = FALSE;} void Init(CVertexBuffer* pVB, UINT primitiveBase); BYTE* Lock(UINT NeededSize, CD3DDDIDX6* pDDI); void Unlock() {} BOOL IsUserMemStream() {return m_bUserMemStream;} void AddVertices(UINT NumVertices) {} void SubVertices(UINT NumVertices) {} void MovePrimitiveBase(int NumVertices) { m_dwPrimitiveBase += NumVertices * m_dwStride; } void SkipVertices(DWORD NumVertices) { m_dwPrimitiveBase += NumVertices * m_dwStride; } protected: BOOL m_bUserMemStream; }; //----------------------------------------------------------------------------- void CTLStreamRO::Init(CVertexBuffer* pVB, UINT primitiveBase) { if (m_pVB) { m_pVB->DecrementUseCount(); m_pVB = NULL; } m_pVB = pVB; if (pVB) { m_bUserMemStream = FALSE; m_pVB->IncrementUseCount(); } else { m_bUserMemStream = TRUE; } m_dwPrimitiveBase = primitiveBase; } //----------------------------------------------------------------------------- // Index stream which is read-only // class CTLIndexStreamRO: public CTLIndexStream { public: CTLIndexStreamRO() {m_dwIndex = __NUMSTREAMS;} void Init(CIndexBuffer* pVB, UINT primitiveBase); BYTE* Lock(UINT NeededSize, CD3DDDIDX6* pDDI); void Unlock() {} void AddVertices(UINT NumVertices) {} void SubVertices(UINT NumVertices) {} void MovePrimitiveBase(int NumVertices) { m_dwPrimitiveBase += NumVertices * m_dwStride; } void SkipVertices(DWORD NumVertices) { m_dwPrimitiveBase += NumVertices * m_dwStride; } }; //----------------------------------------------------------------------------- void CTLIndexStreamRO::Init(CIndexBuffer* pVB, UINT primitiveBase) { if (m_pVBI) { m_pVBI->DecrementUseCount(); m_pVBI = NULL; } m_pVBI = pVB; if (m_pVBI) m_pVBI->IncrementUseCount(); m_dwPrimitiveBase = primitiveBase; } //----------------------------------------------------------------------------- CTLStream::CTLStream(BOOL bWriteOnly) { m_bWriteOnly = bWriteOnly; m_dwSize = 0; m_dwPrimitiveBase = 0; m_dwUsedSize = 0; m_dwIndex = 0; m_Usage = 0; } //----------------------------------------------------------------------------- CTLStream::CTLStream(BOOL bWriteOnly, UINT Usage) { m_bWriteOnly = bWriteOnly; m_dwSize = 0; m_dwPrimitiveBase = 0; m_dwUsedSize = 0; m_dwIndex = 0; m_Usage = Usage; } //----------------------------------------------------------------------------- void CTLStream::Grow(UINT RequiredSize, CD3DDDIDX6* pDDI) { if (RequiredSize > m_dwSize) { // We create the new vertex buffer before releasing the old one to // prevent creating the buffer on the same place in memory DWORD dwUsage = D3DUSAGE_INTERNALBUFFER | D3DUSAGE_DYNAMIC | m_Usage; if (m_bWriteOnly) dwUsage |= D3DUSAGE_WRITEONLY; IDirect3DVertexBuffer8 * pVB; HRESULT ret = CVertexBuffer::Create(pDDI->GetDevice(), RequiredSize, dwUsage, 0, D3DPOOL_DEFAULT, REF_INTERNAL, &pVB); if (ret != DD_OK) { D3D_THROW(ret, "Could not allocate internal vertex buffer"); } if (m_pVB) m_pVB->DecrementUseCount(); m_pVB = static_cast(pVB); m_dwSize = RequiredSize; } } //----------------------------------------------------------------------------- BYTE* CTLStream::Lock(UINT NeededSize, CD3DDDIDX6* pDDI) { HRESULT ret; DXGASSERT(m_dwSize >= m_dwUsedSize); if (NeededSize > m_dwSize - m_dwUsedSize || m_dwUsedSize == 0) { Grow(NeededSize, pDDI); ret = m_pVB->Lock(0, m_dwSize, &m_pData, D3DLOCK_DISCARD | D3DLOCK_NOSYSLOCK); this->Reset(); } else { ret = m_pVB->Lock(0, m_dwSize, &m_pData, D3DLOCK_NOOVERWRITE | D3DLOCK_NOSYSLOCK); } if (ret != DD_OK) { D3D_THROW(ret, "Could not lock internal vertex buffer"); } // m_dwPrimitiveBase could be out of sync with m_dwUsedSize, because // sometimes we re-use vertices (like when clipping line strips). Make // sure that they are in sync. m_dwPrimitiveBase = m_dwUsedSize; return m_pData + m_dwUsedSize; } //----------------------------------------------------------------------------- void CTLStream::Unlock() { m_pVB->Unlock(); } //----------------------------------------------------------------------------- CTLIndexStream::CTLIndexStream() { m_dwSize = 0; m_dwPrimitiveBase = 0; m_dwUsedSize = 0; m_dwIndex = 0; } //----------------------------------------------------------------------------- void CTLIndexStream::Grow(UINT RequiredSize, CD3DDDIDX6* pDDI) { if (RequiredSize > m_dwSize) { // We create the new vertex buffer before releasing the old one to // prevent creating the buffer on the same place in memory DWORD dwUsage = D3DUSAGE_INTERNALBUFFER | D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC; IDirect3DIndexBuffer8 * pVB; HRESULT ret = CIndexBuffer::Create(pDDI->GetDevice(), RequiredSize, dwUsage, D3DFMT_INDEX16, D3DPOOL_DEFAULT, REF_INTERNAL, &pVB); if (ret != DD_OK) { D3D_THROW(ret, "Could not allocate internal index buffer"); } if (m_pVBI) m_pVBI->DecrementUseCount(); m_pVBI = static_cast(pVB); m_dwSize = RequiredSize; } } //----------------------------------------------------------------------------- BYTE* CTLIndexStream::Lock(UINT NeededSize, CD3DDDIDX6* pDDI) { HRESULT ret; DXGASSERT(m_dwSize >= m_dwUsedSize); if (NeededSize > m_dwSize - m_dwUsedSize || m_dwUsedSize == 0) { Grow(NeededSize, pDDI); ret = m_pVBI->Lock(0, m_dwSize, &m_pData, D3DLOCK_DISCARD | D3DLOCK_NOSYSLOCK); this->Reset(); } else { ret = m_pVBI->Lock(0, m_dwSize, &m_pData, D3DLOCK_NOOVERWRITE | D3DLOCK_NOSYSLOCK); } if (ret != DD_OK) { D3D_THROW(ret, "Could not lock internal index buffer"); } // m_dwPrimitiveBase could be out of sync with m_dwUsedSize, because // sometimes we re-use vertices (like when clipping line strips). Make // sure that they are in sync. m_dwPrimitiveBase = m_dwUsedSize; return m_pData + m_dwUsedSize; } //----------------------------------------------------------------------------- BYTE* CTLIndexStream::LockDiscard(UINT NeededSize, CD3DDDIDX6* pDDI) { HRESULT ret; DXGASSERT(m_dwSize >= m_dwUsedSize); Grow(NeededSize, pDDI); ret = m_pVBI->Lock(0, m_dwSize, &m_pData, D3DLOCK_DISCARD | D3DLOCK_NOSYSLOCK); this->Reset(); if (ret != DD_OK) { D3D_THROW(ret, "Could not lock internal index buffer"); } // We have called Reset() so no need to set PrimitiveBase return m_pData; } //----------------------------------------------------------------------------- void CTLIndexStream::Unlock() { m_pVBI->Unlock(); } //----------------------------------------------------------------------------- BYTE* CTLStreamRO::Lock(UINT NeededSize, CD3DDDIDX6* pDDI) { return m_pVB->Data(); } //----------------------------------------------------------------------------- BYTE* CTLIndexStreamRO::Lock(UINT NeededSize, CD3DDDIDX6* pDDI) { return m_pVBI->Data(); } ///////////////////////////////////////////////////////////////////////////// // // // CD3DDDIDX8 // // // ///////////////////////////////////////////////////////////////////////////// const DWORD CD3DDDIDX8::m_dwDummyVertexLength = 10; const DWORD CD3DDDIDX8::m_dwDummyVertexSize = sizeof(D3DVERTEX); CD3DDDIDX8::CD3DDDIDX8() { m_ddiType = D3DDDITYPE_DX8; m_pTLStream = NULL; m_pTLStreamRO = NULL; m_pTLStreamW = NULL; m_pCurrentTLStream = NULL; m_pIndexStream = NULL; m_pTLStreamClip = NULL; m_pCurrentIndexStream = NULL; m_pTLIndexStreamRO = NULL; m_dwInterfaceNumber = 4; m_pvDummyArray = NULL; } //----------------------------------------------------------------------------- CD3DDDIDX8::~CD3DDDIDX8() { // During deletion of the objects below, the Flush could happen. // We have to assing pointers to NULL to prevent accessing objects // during the Flush. m_pCurrentTLStream = NULL; delete m_pTLStreamW; m_pTLStreamW = NULL; delete m_pTLStream; m_pTLStream = NULL; delete m_pTLStreamRO; m_pTLStreamRO = NULL; delete m_pTLIndexStreamRO; m_pTLIndexStreamRO = NULL; delete m_pIndexStream; m_pIndexStream = NULL; delete m_pTLStreamClip; m_pTLStreamClip = NULL; if (m_pvDummyArray) { delete [] m_pvDummyArray; m_pvDummyArray = NULL; } delete m_pPointStream; m_pPointStream = NULL; return; } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::Init" void CD3DDDIDX8::Init(CD3DBase* pDevice) { // CD3DDDIDX6::Init( pDevice ); m_pDevice = pDevice; CreateContext(); GrowCommandBuffer(dwD3DDefaultCommandBatchSize); m_pvDummyArray = (VOID *)new BYTE[m_dwDummyVertexSize*m_dwDummyVertexLength]; if( m_pvDummyArray == NULL ) { D3D_THROW(E_OUTOFMEMORY, "Cannot allocate dummy array"); } // Fill the dp2data structure with initial values dp2data.dwFlags = D3DHALDP2_SWAPCOMMANDBUFFER; dp2data.dwVertexType = 0; // Initial assumption // We always pass this flag to prevent NT kernel from validation of vertex // buffer pointer dp2data.dwFlags |= D3DHALDP2_USERMEMVERTICES; SetDummyData(); ClearBatch(FALSE); m_pTLStream = new CTLStream(FALSE); if (m_pTLStream == NULL) D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal stream m_pTLStream"); m_pTLStreamW = new CTLStream(TRUE); if (m_pTLStreamW == NULL) D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal stream m_pTLStreamW"); m_pTLStreamClip = new CTLStream(TRUE); if (m_pTLStreamClip == NULL) D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal stream m_pTLStreamClip"); m_pIndexStream = new CTLIndexStream(); if (m_pIndexStream == NULL) D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal stream m_pIndexStream"); m_pTLStreamRO = new CTLStreamRO(); if (m_pTLStreamRO == NULL) D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal stream m_pTLStreamRO"); m_pTLIndexStreamRO = new CTLIndexStreamRO(); if (m_pTLIndexStreamRO == NULL) D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal stream m_pTLIndexStreamRO"); m_pTLStream->Grow(__INIT_VERTEX_NUMBER*2*sizeof(D3DTLVERTEX), this); m_pTLStreamW->Grow(__INIT_VERTEX_NUMBER*2*sizeof(D3DTLVERTEX), this); m_pTLStreamClip->Grow(__INIT_VERTEX_NUMBER*2*sizeof(D3DTLVERTEX), this); m_pIndexStream->Grow(__INIT_VERTEX_NUMBER*4, this); m_CurrentVertexShader = 0; m_pPointStream = new CTLStream(FALSE); if (m_pPointStream == NULL) D3D_THROW(E_OUTOFMEMORY, "Cannot allocate internal data structure CTLStream"); #if DBG m_bValidateCommands = FALSE; #endif } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::ValidateDevice" void CD3DDDIDX8::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(); UpdateDirtyStreams(); // 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; } //----------------------------------------------------------------------------- // Sends "dirty" streams to the command buffer // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::UpdateDirtyStreams" void CD3DDDIDX8::UpdateDirtyStreams() { DWORD dwNumStreams = m_pDevice->m_dwNumStreams; if (m_pDevice->m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) { // For software vertex processing we should update only stream 0 // and index stream dwNumStreams = 1; } for(unsigned dwStream = 0, StreamMask = 1; dwStream <= dwNumStreams; dwStream++, StreamMask <<= 1) { // When max number of vertex stream is reached, process index stream if (dwStream == dwNumStreams) { dwStream = __NUMSTREAMS; StreamMask = (1 << __NUMSTREAMS); } BOOL bDirty = (m_pDevice->m_dwStreamDirty & StreamMask) != 0; m_pDevice->m_dwStreamDirty &= ~StreamMask; // reset stage dirty CBuffer *pBuf; if(dwStream < dwNumStreams) { pBuf = m_pDevice->m_pStream[dwStream].m_pVB; } else { pBuf = m_pDevice->m_pIndexStream->m_pVBI; } if(pBuf != 0) { if(pBuf->IsD3DManaged()) { HRESULT result; result = m_pDevice->ResourceManager()->UpdateVideo(pBuf->RMHandle(), &bDirty); if(result != D3D_OK) { D3D_THROW(result, "Resource manager failed to create or update video memory VB/IB"); } } } if (!bDirty) { continue; } if(dwStream < dwNumStreams) { InsertStreamSource(&m_pDevice->m_pStream[dwStream]); CDDIStream &Stream = m_pDDIStream[dwStream]; Stream.m_pStream = &m_pDevice->m_pStream[dwStream]; Stream.m_pBuf = pBuf; Stream.m_dwStride = m_pDevice->m_pStream[dwStream].m_dwStride; } else { DXGASSERT(dwStream == __NUMSTREAMS); InsertIndices(m_pDevice->m_pIndexStream); CDDIStream &Stream = m_pDDIStream[dwStream]; Stream.m_pStream = m_pDevice->m_pIndexStream; Stream.m_pBuf = pBuf; Stream.m_dwStride = m_pDevice->m_pIndexStream->m_dwStride; } } } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::LockVB" HRESULT __declspec(nothrow) CD3DDDIDX8::LockVB(CDriverVertexBuffer *pVB, DWORD dwFlags) { HRESULT hr; if (pVB->GetCachedDataPointer() != 0) // if lock was cached { DXGASSERT((dwFlags & (D3DLOCK_READONLY | D3DLOCK_NOOVERWRITE)) == 0); DXGASSERT((pVB->GetBufferDesc()->Usage & D3DUSAGE_DYNAMIC) != 0); hr = pVB->UnlockI(); if(FAILED(hr)) { DPF_ERR("Driver failed to unlock a vertex buffer" " when attempting to re-cache the lock."); pVB->SetCachedDataPointer(0); return hr; } } hr = pVB->LockI(dwFlags | D3DLOCK_NOSYSLOCK); if (FAILED(hr)) { DPF_ERR("Driver failed to lock a vertex buffer" " when attempting to cache the lock."); pVB->SetCachedDataPointer(0); return hr; } return D3D_OK; } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::UnlockVB" HRESULT __declspec(nothrow) CD3DDDIDX8::UnlockVB(CDriverVertexBuffer *pVB) { return pVB->UnlockI(); } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::SetTSS" void CD3DDDIDX8::SetTSS(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, DWORD dwValue) { // Filter unsupported states if (dwState >= m_pDevice->m_tssMax) return; 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); D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); 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; D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); // 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); } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::CreatePixelShader" void CD3DDDIDX8::CreatePixelShader(CONST DWORD* pdwFunction, DWORD dwCodeSize, DWORD dwHandle) { FlushStates(); LPD3DHAL_DP2CREATEPIXELSHADER pData; pData = (LPD3DHAL_DP2CREATEPIXELSHADER) GetHalBufferPointer(D3DDP2OP_CREATEPIXELSHADER, sizeof(*pData) + dwCodeSize); pData->dwHandle = dwHandle; pData->dwCodeSize = dwCodeSize; LPBYTE p = (LPBYTE)&pData[1]; memcpy(p, pdwFunction, dwCodeSize); FlushStates(TRUE,FALSE); } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::SetPixelShader" void CD3DDDIDX8::SetPixelShader( DWORD dwHandle ) { LPD3DHAL_DP2PIXELSHADER pData; pData = (LPD3DHAL_DP2PIXELSHADER) GetHalBufferPointer(D3DDP2OP_SETPIXELSHADER, sizeof(*pData)); pData->dwHandle = dwHandle; } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::DeletePixelShader" void CD3DDDIDX8::DeletePixelShader(DWORD dwHandle) { LPD3DHAL_DP2PIXELSHADER pData; pData = (LPD3DHAL_DP2PIXELSHADER) GetHalBufferPointer(D3DDP2OP_DELETEPIXELSHADER, sizeof(*pData)); pData->dwHandle = dwHandle; } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::SetPixelShaderConstant" void CD3DDDIDX8::SetPixelShaderConstant(DWORD dwRegister, CONST VOID* data, DWORD count) { const DWORD size = count << 4; LPD3DHAL_DP2SETPIXELSHADERCONST pData; pData = (LPD3DHAL_DP2SETPIXELSHADERCONST) GetHalBufferPointer(D3DDP2OP_SETPIXELSHADERCONST, sizeof(*pData) + size); pData->dwRegister = dwRegister; pData->dwCount = count; memcpy(pData+1, data, size); } //----------------------------------------------------------------------------- // Inserts SetStreamSource command into the command buffer // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::InsertStreamSource" void CD3DDDIDX8::InsertStreamSource(CVStream* pStream) { if (pStream->IsUserMemStream()) { InsertStreamSourceUP(pStream->m_dwStride); return; } LPD3DHAL_DP2SETSTREAMSOURCE pData; pData = (LPD3DHAL_DP2SETSTREAMSOURCE) GetHalBufferPointer(D3DDP2OP_SETSTREAMSOURCE, sizeof(*pData)); pData->dwStream = pStream->m_dwIndex; pData->dwVBHandle = pStream->m_pVB != 0 ? pStream->m_pVB->DriverAccessibleDrawPrimHandle() : 0; pData->dwStride = pStream->m_dwStride; CDDIStream* pDDIStream = &m_pDDIStream[pStream->m_dwIndex]; pDDIStream->m_dwStride = pStream->m_dwStride; pDDIStream->m_pStream = pStream; pDDIStream->m_pBuf = pStream->m_pVB; if (pStream->m_pVB != 0) { pStream->m_pVB->Batch(); } } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::InsertStreamSourceUP" void CD3DDDIDX8::InsertStreamSourceUP(DWORD dwStride) { // User memory source LPD3DHAL_DP2SETSTREAMSOURCEUM pData; pData = (LPD3DHAL_DP2SETSTREAMSOURCEUM) GetHalBufferPointer(D3DDP2OP_SETSTREAMSOURCEUM, sizeof(*pData)); pData->dwStream = 0; pData->dwStride = dwStride; CDDIStream* pDDIStream = &m_pDDIStream[0]; pDDIStream->m_dwStride = dwStride; pDDIStream->m_pStream = NULL; pDDIStream->m_pBuf = NULL; } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::InsertIndices" void CD3DDDIDX8::InsertIndices(CVIndexStream* pStream) { LPD3DHAL_DP2SETINDICES pData; pData = (LPD3DHAL_DP2SETINDICES) GetHalBufferPointer(D3DDP2OP_SETINDICES, sizeof(*pData)); pData->dwVBHandle = pStream->m_pVBI != 0 ? pStream->m_pVBI->DriverAccessibleDrawPrimHandle() : 0; pData->dwStride = pStream->m_dwStride; m_pDDIStream[__NUMSTREAMS].m_dwStride = pStream->m_dwStride; m_pDDIStream[__NUMSTREAMS].m_pStream = pStream; m_pDDIStream[__NUMSTREAMS].m_pBuf = pStream->m_pVBI; if(pStream->m_pVBI != 0) { pStream->m_pVBI->Batch(); } } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8_DrawPrimitive" void CD3DDDIDX8_DrawPrimitive(CD3DBase* pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) { #if DBG if (!(pDevice->BehaviorFlags() & D3DCREATE_PUREDEVICE)) { CD3DHal* pDev = static_cast(pDevice); UINT nVer = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount); pDev->ValidateDraw2(PrimitiveType, StartVertex, PrimitiveCount, nVer, FALSE); } #endif // DBG CD3DDDIDX8* pDDI = static_cast(pDevice->m_pDDI); if(pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { pDevice->UpdateTextures(); pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } if (pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE) { pDDI->UpdateDirtyStreams(); pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE; } if (pDDI->bDP2CurrCmdOP == D3DDP2OP_DRAWPRIMITIVE) { // Last instruction is a DrawPrimitive, append this one to it // // First check if the new instruction is a TRIANGLELIST. If it is, // AND if the new StartVertex = prev StartVertex + prev PrimitiveCount * 3 // then we can simply bump up the prev primitive count. This makes // drivers go a LOT faster. (snene - 12/00) // //!!!!!!!!!!!!!!!!!!!!!!!!!!ALERT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // The following code READS BACK from the batched command. This is // NOT a problem for sysmem command buffers in DX8. However, going // forward, if we ever implement vidmem command buffers, we need // to FIX this code to not read back. (snene - 12/00) LPD3DHAL_DP2DRAWPRIMITIVE pData = (LPD3DHAL_DP2DRAWPRIMITIVE) ((LPBYTE)pDDI->lpvDP2Commands + pDDI->dwDP2CommandLength - sizeof(D3DHAL_DP2DRAWPRIMITIVE) + pDDI->dp2data.dwCommandOffset); if(pData->primType == D3DPT_TRIANGLELIST && pData->primType == PrimitiveType && pData->VStart + pData->PrimitiveCount * 3 == StartVertex && pData->PrimitiveCount + PrimitiveCount >= pData->PrimitiveCount) // overflow { pData->PrimitiveCount += PrimitiveCount; return; } //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if (pDDI->dwDP2CommandLength + sizeof(D3DHAL_DP2DRAWPRIMITIVE) <= pDDI->dwDP2CommandBufSize) { ++pData; pDDI->lpDP2CurrCommand->wStateCount = ++pDDI->wDP2CurrCmdCnt; pData->primType = PrimitiveType; pData->VStart = StartVertex; pData->PrimitiveCount = PrimitiveCount; pDDI->dwDP2CommandLength += sizeof(D3DHAL_DP2DRAWPRIMITIVE); D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)pDDI->lpDP2CurrCommand); return; } } // Check for space if (pDDI->dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2DRAWPRIMITIVE) > pDDI->dwDP2CommandBufSize) { pDDI->FlushStates(); } // Add new DrawPrimitive instruction pDDI->lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)pDDI->lpvDP2Commands + pDDI->dwDP2CommandLength + pDDI->dp2data.dwCommandOffset); pDDI->lpDP2CurrCommand->bCommand = D3DDP2OP_DRAWPRIMITIVE; pDDI->bDP2CurrCmdOP = D3DDP2OP_DRAWPRIMITIVE; pDDI->lpDP2CurrCommand->bReserved = 0; pDDI->lpDP2CurrCommand->wStateCount = 1; pDDI->wDP2CurrCmdCnt = 1; D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)pDDI->lpDP2CurrCommand); // Add DrawPrimitive data LPD3DHAL_DP2DRAWPRIMITIVE pData; pData = (LPD3DHAL_DP2DRAWPRIMITIVE)(pDDI->lpDP2CurrCommand + 1); pData->primType = PrimitiveType; pData->VStart = StartVertex; pData->PrimitiveCount = PrimitiveCount; pDDI->dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2DRAWPRIMITIVE); } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::SetDummyData" void CD3DDDIDX8::SetDummyData() { dp2data.dwVertexSize = m_dwDummyVertexSize; dp2data.lpVertices = m_pvDummyArray; dp2data.dwVertexLength = m_dwDummyVertexLength; } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8_DrawIndexedPrimitive" void CD3DDDIDX8_DrawIndexedPrimitive(CD3DBase* pDevice, D3DPRIMITIVETYPE PrimitiveType, UINT BaseVertexIndex, UINT MinIndex, UINT NumVertices, UINT StartIndex, UINT PrimitiveCount) { #if DBG if (!(pDevice->BehaviorFlags() & D3DCREATE_PUREDEVICE)) { CD3DHal* pDev = static_cast(pDevice); pDev->ValidateDraw2(PrimitiveType, MinIndex + BaseVertexIndex, PrimitiveCount, NumVertices, TRUE, StartIndex); } #endif // DBG CD3DDDIDX8* pDDI = static_cast(pDevice->m_pDDI); if(pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { pDevice->UpdateTextures(); pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } if (pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE) { pDDI->UpdateDirtyStreams(); pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE; } if (pDDI->bDP2CurrCmdOP == D3DDP2OP_DRAWINDEXEDPRIMITIVE) { // Last instruction is a DrawIndexedPrimitive, append this one to it // // First check if the new instruction is a TRIANGLELIST. If it is, // AND if the new StartIndex = prev StartIndex + prev PrimitiveCount * 3 // AND if the new BaseVertexIndex = prev BaseVertexIndex // then we can simply bump up the prev primitive count. This makes // drivers go a LOT faster. (snene - 12/00) // //!!!!!!!!!!!!!!!!!!!!!!!!!!ALERT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // The following code READS BACK from the batched command. This is // NOT a problem for sysmem command buffers in DX8. However, going // forward, if we ever implement vidmem command buffers, we need // to FIX this code to not read back. (snene - 12/00) LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE pData = (LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE) ((LPBYTE)pDDI->lpvDP2Commands + pDDI->dwDP2CommandLength - sizeof(D3DHAL_DP2DRAWINDEXEDPRIMITIVE) + pDDI->dp2data.dwCommandOffset); if(pData->primType == D3DPT_TRIANGLELIST && pData->primType == PrimitiveType && pData->BaseVertexIndex == BaseVertexIndex && pData->StartIndex + pData->PrimitiveCount * 3 == StartIndex && pData->PrimitiveCount + PrimitiveCount >= pData->PrimitiveCount) // overflow { UINT mnidx = min(pData->MinIndex, MinIndex); UINT mxidx = max(pData->MinIndex + pData->NumVertices, MinIndex + NumVertices); if(mxidx - mnidx <= pData->NumVertices + NumVertices) { pData->NumVertices = mxidx - mnidx; pData->MinIndex = mnidx; pData->PrimitiveCount += PrimitiveCount; return; } } //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if (pDDI->dwDP2CommandLength + sizeof(D3DHAL_DP2DRAWINDEXEDPRIMITIVE) <= pDDI->dwDP2CommandBufSize) { ++pData; pDDI->lpDP2CurrCommand->wStateCount = ++pDDI->wDP2CurrCmdCnt; pData->BaseVertexIndex = BaseVertexIndex; pData->primType = PrimitiveType; pData->PrimitiveCount = PrimitiveCount; pData->MinIndex = MinIndex; pData->NumVertices = NumVertices; pData->StartIndex = StartIndex; pDDI->dwDP2CommandLength += sizeof(D3DHAL_DP2DRAWINDEXEDPRIMITIVE); D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)pDDI->lpDP2CurrCommand); return; } } // Check for space if (pDDI->dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2DRAWINDEXEDPRIMITIVE) > pDDI->dwDP2CommandBufSize) { pDDI->FlushStates(); } // Add new DrawIndexedPrimitive instruction pDDI->lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)pDDI->lpvDP2Commands + pDDI->dwDP2CommandLength + pDDI->dp2data.dwCommandOffset); pDDI->lpDP2CurrCommand->bCommand = D3DDP2OP_DRAWINDEXEDPRIMITIVE; pDDI->bDP2CurrCmdOP = D3DDP2OP_DRAWINDEXEDPRIMITIVE; pDDI->lpDP2CurrCommand->bReserved = 0; pDDI->lpDP2CurrCommand->wStateCount = 1; pDDI->wDP2CurrCmdCnt = 1; D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)pDDI->lpDP2CurrCommand); // Add DrawIndexedPrimitive data LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE pData; pData = (LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE)(pDDI->lpDP2CurrCommand + 1); pData->BaseVertexIndex = BaseVertexIndex; pData->primType = PrimitiveType; pData->PrimitiveCount = PrimitiveCount; pData->MinIndex = MinIndex; pData->NumVertices = NumVertices; pData->StartIndex = StartIndex; pDDI->dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2DRAWINDEXEDPRIMITIVE); #if DBG // if (m_bValidateCommands) // ValidateCommand(lpDP2CurrCommand); #endif } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::DrawPrimitiveUP" void CD3DDDIDX8::DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount) { UINT NumVertices = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount); if (NumVertices > LOWVERTICESNUMBER) { if (m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE) { UpdateDirtyStreams(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE; } this->FlushStates(); dp2data.dwVertexType = 0; dp2data.dwVertexSize = m_pDevice->m_pStream[0].m_dwStride; dp2data.lpVertices = m_pDevice->m_pStream[0].m_pData; dp2data.dwVertexLength = NumVertices; try { InsertStreamSourceUP(m_pDevice->m_pStream[0].m_dwStride); CD3DDDIDX8_DrawPrimitive(m_pDevice, PrimitiveType, 0, PrimitiveCount); this->FlushStates(); } catch( HRESULT hr ) { SetDummyData(); throw hr; } SetDummyData(); } else { // Copy vertices to the internal TL buffer UINT VertexSize = m_pDevice->m_pStream[0].m_dwStride; // When vertex size has been changed we need to start from the // beginning of the vertex buffer to correctly handle vertex offsets if (m_pTLStreamW->GetPrimitiveBase() % VertexSize) { this->FlushStates(); m_pTLStreamW->Reset(); } // Copy vertices into the internal write only buffer m_pTLStreamW->SetVertexSize(VertexSize); UINT VertexPoolSize = VertexSize * NumVertices; LPVOID lpvOut = m_pTLStreamW->Lock(VertexPoolSize, this); UINT StartVertex = m_pTLStreamW->GetPrimitiveBase() / VertexSize; memcpy(lpvOut, m_pDevice->m_pStream[0].m_pData, VertexPoolSize); m_pTLStreamW->Unlock(); m_pTLStreamW->SkipVertices(NumVertices); // To prevent overriding of stream 0 we clear D3DRT_NEED_VB_UPDATE and // stream dirty bit. We need to clear the stream dirty bit, because during // UpdateTextures D3DRT_NEED_VB_UPDATE could be set again DWORD dwRuntimeFlags = m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE; m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE; m_pDevice->m_dwStreamDirty &= ~1; if (m_pDDIStream[0].m_pBuf != m_pTLStreamW->m_pVB || m_pDDIStream[0].m_dwStride != m_pTLStreamW->m_dwStride) { InsertStreamSource(m_pTLStreamW); } #if DBG // Need this to pass validation m_pDevice->m_pStream[0].m_dwNumVertices = StartVertex + NumVertices; #endif // Insert drawing command CD3DDDIDX8_DrawPrimitive(m_pDevice, PrimitiveType, StartVertex, PrimitiveCount); m_pDevice->m_dwRuntimeFlags |= dwRuntimeFlags; } } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::DrawIndexedPrimitiveUP" void CD3DDDIDX8::DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount) { if (NumVertices > LOWVERTICESNUMBER) { if (m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE) { UpdateDirtyStreams(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE; } this->FlushStates(); dp2data.dwVertexType = 0; dp2data.dwVertexSize = m_pDevice->m_pStream[0].m_dwStride; dp2data.lpVertices = m_pDevice->m_pStream[0].m_pData; dp2data.dwVertexLength = NumVertices; try { InsertStreamSourceUP(m_pDevice->m_pStream[0].m_dwStride); UINT NumIndices = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount); m_pIndexStream->SetVertexSize(m_pDevice->m_pIndexStream->m_dwStride); // Always start from the beginning of the index stream // Copy indices into the internal stream DWORD dwIndicesByteCount = NumIndices * m_pIndexStream->m_dwStride; BYTE* pIndexData = m_pIndexStream->LockDiscard(dwIndicesByteCount, this); memcpy(pIndexData, m_pDevice->m_pIndexStream->m_pData, dwIndicesByteCount); m_pIndexStream->Unlock(); InsertIndices(m_pIndexStream); CD3DDDIDX8_DrawIndexedPrimitive(m_pDevice, PrimitiveType, 0, MinVertexIndex, NumVertices, 0, PrimitiveCount); this->FlushStates(); } catch( HRESULT hr ) { SetDummyData(); throw hr; } SetDummyData(); } else { // Copy user data into internal buffers UINT VertexSize = m_pDevice->m_pStream[0].m_dwStride; UINT IndexSize = m_pDevice->m_pIndexStream->m_dwStride; if ((m_pTLStreamW->GetPrimitiveBase() % VertexSize) || (m_pIndexStream->GetPrimitiveBase() % IndexSize)) { this->FlushStates(); m_pTLStreamW->Reset(); m_pIndexStream->Reset(); } // Copy vertices into the internal write only buffer m_pTLStreamW->SetVertexSize(VertexSize); UINT VertexPoolSize = VertexSize * NumVertices; LPVOID lpvOut = m_pTLStreamW->Lock(VertexPoolSize, this); UINT StartVertex = m_pTLStreamW->GetPrimitiveBase() / VertexSize; UINT FirstVertexOffset = MinVertexIndex * VertexSize; memcpy(lpvOut, m_pDevice->m_pStream[0].m_pData + FirstVertexOffset, VertexPoolSize); m_pTLStreamW->Unlock(); m_pTLStreamW->SkipVertices(NumVertices); // To prevent overriding of stream 0 we clear D3DRT_NEED_VB_UPDATE and // stream dirty bit. We need to clear the stream dirty bit, because during // UpdateTextures D3DRT_NEED_VB_UPDATE could be set again DWORD dwRuntimeFlags = m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE; m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE; m_pDevice->m_dwStreamDirty &= ~(1 | (1 << __NUMSTREAMS)); if (m_pDDIStream[0].m_pBuf != m_pTLStreamW->m_pVB || m_pDDIStream[0].m_dwStride != m_pTLStreamW->m_dwStride) { InsertStreamSource(m_pTLStreamW); } // Copy indices into the internal buffer. Re-base indices if necessery. m_pIndexStream->SetVertexSize(IndexSize); UINT NumIndices = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount); UINT IndexPoolSize = IndexSize * NumIndices; lpvOut = m_pIndexStream->Lock(IndexPoolSize, this); UINT StartIndex = m_pIndexStream->GetPrimitiveBase() / IndexSize; memcpy(lpvOut, m_pDevice->m_pIndexStream->m_pData, IndexPoolSize); m_pIndexStream->Unlock(); m_pIndexStream->SkipVertices(NumIndices); if (m_pDDIStream[__NUMSTREAMS].m_pBuf != m_pIndexStream->m_pVBI || m_pDDIStream[__NUMSTREAMS].m_dwStride != m_pIndexStream->m_dwStride) { InsertIndices(m_pIndexStream); } #if DBG // Need this to pass validation m_pDevice->m_pStream[0].m_dwNumVertices = StartVertex + NumVertices; m_pDevice->m_pIndexStream->m_dwNumVertices = StartIndex + NumIndices; #endif // Draw primitive CD3DDDIDX8_DrawIndexedPrimitive(m_pDevice, PrimitiveType, StartVertex - MinVertexIndex, MinVertexIndex, NumVertices, StartIndex, PrimitiveCount); m_pDevice->m_dwRuntimeFlags |= dwRuntimeFlags; } } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::DrawRectPatch" void CD3DDDIDX8::DrawRectPatch(UINT Handle, CONST D3DRECTPATCH_INFO *pSurf, CONST FLOAT *pNumSegs) { if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { m_pDevice->UpdateTextures(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } if (m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE) { UpdateDirtyStreams(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE; } LPD3DHAL_DP2DRAWRECTPATCH pData; pData = (LPD3DHAL_DP2DRAWRECTPATCH) GetHalBufferPointer(D3DDP2OP_DRAWRECTPATCH, sizeof(*pData) + (pSurf != 0 ? sizeof(D3DRECTPATCH_INFO) : 0) + (pNumSegs != 0 ? sizeof(FLOAT) * 4 : 0)); pData->Handle = Handle; DWORD offset; if(pNumSegs != 0) { offset = sizeof(FLOAT) * 4; memcpy(pData + 1, pNumSegs, offset); pData->Flags = RTPATCHFLAG_HASSEGS; } else { pData->Flags = 0; offset = 0; } if(pSurf != 0) { memcpy((BYTE*)(pData + 1) + offset, pSurf, sizeof(D3DRECTPATCH_INFO)); pData->Flags |= RTPATCHFLAG_HASINFO; } } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::DrawTriSurface" void CD3DDDIDX8::DrawTriPatch(UINT Handle, CONST D3DTRIPATCH_INFO *pSurf, CONST FLOAT *pNumSegs) { if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { m_pDevice->UpdateTextures(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } if (m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE) { UpdateDirtyStreams(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE; } LPD3DHAL_DP2DRAWTRIPATCH pData; pData = (LPD3DHAL_DP2DRAWTRIPATCH) GetHalBufferPointer(D3DDP2OP_DRAWTRIPATCH, sizeof(*pData) + (pSurf != 0 ? sizeof(D3DTRIPATCH_INFO) : 0) + (pNumSegs != 0 ? sizeof(FLOAT) * 3 : 0)); pData->Handle = Handle; DWORD offset; if(pNumSegs != 0) { offset = sizeof(FLOAT) * 3; memcpy(pData + 1, pNumSegs, offset); pData->Flags = RTPATCHFLAG_HASSEGS; } else { pData->Flags = 0; offset = 0; } if(pSurf != 0) { memcpy((BYTE*)(pData + 1) + offset, pSurf, sizeof(D3DTRIPATCH_INFO)); pData->Flags |= RTPATCHFLAG_HASINFO; } } //----------------------------------------------------------------------------- // This function prepares the batch for new primitive. // Called only if vertices from user memory are NOT used for rendering // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::StartPrimVB" void CD3DDDIDX8::StartPrimVB(D3DFE_PROCESSVERTICES * pv, CVStream* pStream, DWORD dwStartVertex) { SetWithinPrimitive(TRUE); UINT size = dwStartVertex * pv->dwOutputSize; if (pStream) m_pTLStreamRO->Init(pStream->m_pVB, size); else m_pTLStreamRO->Init(NULL, size); m_pTLStreamRO->SetVertexSize(pv->dwOutputSize); m_pCurrentTLStream = m_pTLStreamRO; } //----------------------------------------------------------------------------- // This function prepares the batch for new primitive. // Called only if vertices from user memory are NOT used for rendering // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::StartIndexPrimVB" void CD3DDDIDX8::StartIndexPrimVB(CVIndexStream* pStream, UINT StartIndex, UINT IndexSize) { m_pTLIndexStreamRO->Init(pStream->m_pVBI, StartIndex * IndexSize); m_pTLIndexStreamRO->SetVertexSize(IndexSize); m_pCurrentIndexStream = m_pTLIndexStreamRO; } //----------------------------------------------------------------------------- // 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->dwOutputSize // Sets "within primitive" to TRUE // Returns: // TL buffer address // // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::StartPrimTL" LPVOID CD3DDDIDX8::StartPrimTL(D3DFE_PROCESSVERTICES * pv, DWORD dwVertexPoolSize, BOOL bWriteOnly) { CTLStream* pStream = bWriteOnly? m_pTLStreamW : m_pTLStream; LPVOID p = pStream->Lock(dwVertexPoolSize, this); pStream->SetVertexSize(pv->dwOutputSize); m_pCurrentTLStream = pStream; SetWithinPrimitive(TRUE); return p; } //--------------------------------------------------------------------- // Uses the following members of D3DFE_PROCESSVERTICES: // primType // dwNumVertices // dwNumPrimitives // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::DrawPrim" void CD3DDDIDX8::DrawPrim(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; } if (m_pDDIStream[0].m_pBuf != static_cast(m_pCurrentTLStream->m_pVB) || pv->dwOutputSize != m_pDDIStream[0].m_dwStride) { InsertStreamSource(m_pCurrentTLStream); // API stream should be set dirty, in case it is later passed to DDI directly m_pDevice->m_dwStreamDirty |= 1; m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; } if (pv->primType == D3DPT_POINTLIST && pv->dwDeviceFlags & D3DDEV_DOPOINTSPRITEEMULATION) { DrawPrimPS(pv); return; } LPD3DHAL_DP2DRAWPRIMITIVE2 pData; pData = (LPD3DHAL_DP2DRAWPRIMITIVE2) GetHalBufferPointer(D3DDP2OP_DRAWPRIMITIVE2, sizeof(*pData)); pData->primType = pv->primType; pData->FirstVertexOffset = m_pCurrentTLStream->GetPrimitiveBase(); pData->PrimitiveCount = pv->dwNumPrimitives; m_pCurrentTLStream->SkipVertices(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 // dwIndexSize // lpwIndices // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::DrawIndexPrim" void CD3DDDIDX8::DrawIndexPrim(D3DFE_PROCESSVERTICES* pv) { #ifdef DEBUG_PIPELINE if (g_DebugFlags & __DEBUG_NORENDERING) return; #endif this->dwDP2Flags |= D3DDDI_INDEXEDPRIMDRAWN; if (m_pCurrentIndexStream == m_pIndexStream) { // We always copy user provided indices to the internal index stream. // Therefore we have to check the available stream size and do Lock/Unlock DWORD dwIndicesByteCount = pv->dwNumIndices * pv->dwIndexSize; // We cannot mix DWORD and WORD indices because of alignment issues // on ia64 if (m_pIndexStream->GetVertexSize() != pv->dwIndexSize) { this->FlushStates(); m_pIndexStream->Reset(); m_pIndexStream->SetVertexSize(pv->dwIndexSize); } BYTE* pIndexData = m_pIndexStream->Lock(dwIndicesByteCount, this); memcpy(pIndexData, pv->lpwIndices, dwIndicesByteCount); m_pIndexStream->Unlock(); } if (m_pCurrentIndexStream->m_pVBI->IsD3DManaged()) { if (m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_VB_UPDATE) { BOOL bDirty = FALSE; HRESULT result = m_pDevice->ResourceManager()->UpdateVideo(m_pCurrentIndexStream->m_pVBI->RMHandle(), &bDirty); if(result != D3D_OK) { D3D_THROW(result, "Resource manager failed to create or update video memory IB"); } if((m_pDevice->m_dwStreamDirty & (1 << __NUMSTREAMS)) != 0 || bDirty) { InsertIndices(m_pCurrentIndexStream); CDDIStream &Stream = m_pDDIStream[__NUMSTREAMS]; Stream.m_pStream = m_pCurrentIndexStream; Stream.m_pBuf = m_pCurrentIndexStream->m_pVBI; Stream.m_dwStride = m_pCurrentIndexStream->m_dwStride; m_pDevice->m_dwStreamDirty &= ~(1 << __NUMSTREAMS); // reset stage dirty } m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_VB_UPDATE; } } else { if (m_pDDIStream[__NUMSTREAMS].m_pBuf != static_cast(m_pCurrentIndexStream->m_pVBI) || pv->dwIndexSize != m_pDDIStream[__NUMSTREAMS].m_dwStride) { m_pCurrentIndexStream->SetVertexSize(pv->dwIndexSize); InsertIndices(m_pCurrentIndexStream); // API stream should be set dirty, in case it is later passed to DDI directly m_pDevice->m_dwStreamDirty |= (1 << __NUMSTREAMS); m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams() } } if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { m_pDevice->UpdateTextures(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } if (m_pDDIStream[0].m_pBuf != static_cast(m_pCurrentTLStream->m_pVB) || pv->dwOutputSize != m_pDDIStream[0].m_dwStride) { m_pDDIStream[0].m_dwStride = pv->dwOutputSize; InsertStreamSource(m_pCurrentTLStream); // API stream should be set dirty, in case it is later passed to DDI directly m_pDevice->m_dwStreamDirty |= 1; m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams() } LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2 pData; pData = (LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2) GetHalBufferPointer(D3DDP2OP_DRAWINDEXEDPRIMITIVE2, sizeof(*pData)); pData->primType = pv->primType; pData->BaseVertexOffset = m_BaseVertexIndex; pData->MinIndex = m_MinVertexIndex; pData->NumVertices = m_NumVertices; pData->StartIndexOffset = m_pCurrentIndexStream->GetPrimitiveBase(); pData->PrimitiveCount = pv->dwNumPrimitives; m_pCurrentIndexStream->SkipVertices(pv->dwNumIndices); } //----------------------------------------------------------------------------- // 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 "CD3DDDIDX8::DrawClippedPrim" void CD3DDDIDX8::DrawClippedPrim(D3DFE_PROCESSVERTICES* pv) { #ifdef DEBUG_PIPELINE if (g_DebugFlags & __DEBUG_NORENDERING) return; #endif if (m_pDDIStream[0].m_pBuf != static_cast(m_pTLStreamClip->m_pVB) || pv->dwOutputSize != m_pDDIStream[0].m_dwStride) { m_pTLStreamClip->SetVertexSize(pv->dwOutputSize); InsertStreamSource(m_pTLStreamClip); // API stream should be set dirty, in case it is later passed to DDI directly m_pDevice->m_dwStreamDirty |= 1; m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams() } if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { m_pDevice->UpdateTextures(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } DWORD dwVertexPoolSize = pv->dwNumVertices * pv->dwOutputSize; LPVOID pVertices; 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; } // Lock should be before GetPrimitiveBase(), because the primitive // base could be changed during Lock() pVertices = m_pTLStreamClip->Lock(dwVertexPoolSize, this); LPD3DHAL_CLIPPEDTRIANGLEFAN pData; pData = (LPD3DHAL_CLIPPEDTRIANGLEFAN) GetHalBufferPointer(D3DDP2OP_CLIPPEDTRIANGLEFAN, sizeof(*pData)); pData->FirstVertexOffset = m_pTLStreamClip->GetPrimitiveBase(); pData->PrimitiveCount = pv->dwNumPrimitives; if (pv->lpdwRStates[D3DRENDERSTATE_FILLMODE] != D3DFILL_WIREFRAME) { // Mark all exterior edges visible pData->dwEdgeFlags = 0xFFFFFFFF; } else { pData->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) pData->dwEdgeFlags |= (1 << i); } } } else { // Lock should be before GetPrimitiveBase(), because the primitive // base could be changed during Lock() pVertices = m_pTLStreamClip->Lock(dwVertexPoolSize, this); #if DBG if (pv->primType != D3DPT_LINELIST) { D3D_THROW_FAIL("Internal error - invalid primitive type"); } #endif LPD3DHAL_DP2DRAWPRIMITIVE2 pData; pData = (LPD3DHAL_DP2DRAWPRIMITIVE2) GetHalBufferPointer(D3DDP2OP_DRAWPRIMITIVE2, sizeof(*pData)); pData->primType = D3DPT_LINELIST; pData->FirstVertexOffset = m_pTLStreamClip->GetPrimitiveBase(); pData->PrimitiveCount = pv->dwNumPrimitives; } // Copy vertices to the clipped stream memcpy(pVertices, pv->lpvOut, dwVertexPoolSize); m_pTLStreamClip->Unlock(); m_pTLStreamClip->SkipVertices(pv->dwNumVertices); #if DBG if (m_bValidateCommands) ValidateCommand(lpDP2CurrCommand); #endif } //----------------------------------------------------------------------------- // This function is called whe software vertex processing is used // Handle should be always legacy // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::SetVertexShader" void CD3DDDIDX8::SetVertexShader( DWORD dwHandle ) { DXGASSERT(D3DVSD_ISLEGACY(dwHandle)); if (dwHandle != m_CurrentVertexShader) { m_CurrentVertexShader = dwHandle; LPD3DHAL_DP2VERTEXSHADER pData; pData = (LPD3DHAL_DP2VERTEXSHADER) GetHalBufferPointer(D3DDP2OP_SETVERTEXSHADER, sizeof(*pData)); { // Drivers do not need to know about D3DFVF_LASTBETA_UBYTE4 bit dwHandle &= ~D3DFVF_LASTBETA_UBYTE4; } pData->dwHandle = dwHandle; } } //----------------------------------------------------------------------------- // 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 "CD3DDDIDX8::SetVertexShaderHW" void CD3DDDIDX8::SetVertexShaderHW( DWORD dwHandle ) { m_CurrentVertexShader = dwHandle; LPD3DHAL_DP2VERTEXSHADER pData; pData = (LPD3DHAL_DP2VERTEXSHADER) GetHalBufferPointer(D3DDP2OP_SETVERTEXSHADER, sizeof(*pData)); if( D3DVSD_ISLEGACY(dwHandle) ) { // Drivers do not need to know about D3DFVF_LASTBETA_UBYTE4 bit dwHandle &= ~D3DFVF_LASTBETA_UBYTE4; } pData->dwHandle = dwHandle; } //----------------------------------------------------------------------------- // Point sprites are drawn as indexed triangle list // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::StartPointSprites" void CD3DDDIDX8::StartPointSprites() { D3DFE_PROCESSVERTICES* pv = static_cast(m_pDevice)->m_pv; // For StartPrimTL we should use vertex size, which will go to the driver DWORD tmpVertexSize = pv->dwOutputSize; pv->dwOutputSize = m_dwOutputSizePS; // Set new output vertex shader for the DDI SetVertexShader(m_dwVIDOutPS); // Reserve place for the output vertices const UINT size = NUM_SPRITES_IN_BATCH * 4 * pv->dwOutputSize; m_pCurSpriteVertex = (BYTE*)StartPrimTL(pv, size, TRUE); // Restore vertex size, which is size before point sprite emulation pv->dwOutputSize = tmpVertexSize; // Index stream used to hold indices m_pCurrentIndexStream = m_pIndexStream; pv->dwIndexSize = 2; // Reserve place for indices UINT count = NUM_SPRITES_IN_BATCH * 2 * 6; m_pCurPointSpriteIndex = (WORD*)m_pIndexStream->Lock(count, this); m_CurNumberOfSprites = 0; SetWithinPrimitive(TRUE); } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::EndPointSprites" void CD3DDDIDX8::EndPointSprites() { D3DFE_PROCESSVERTICES* pv = static_cast(m_pDevice)->m_pv; m_pCurrentIndexStream->Unlock(); m_pCurrentTLStream->Unlock(); if (m_CurNumberOfSprites) { if (m_pDDIStream[__NUMSTREAMS].m_pBuf != static_cast(m_pCurrentIndexStream->m_pVBI) || pv->dwIndexSize != m_pDDIStream[__NUMSTREAMS].m_dwStride) { m_pCurrentIndexStream->SetVertexSize(pv->dwIndexSize); InsertIndices(m_pCurrentIndexStream); } if (m_pDDIStream[0].m_pBuf != static_cast(m_pCurrentTLStream->m_pVB) || m_dwOutputSizePS != m_pDDIStream[0].m_dwStride) { InsertStreamSource(m_pCurrentTLStream); } if(m_pDevice->m_dwRuntimeFlags & D3DRT_NEED_TEXTURE_UPDATE) { m_pDevice->UpdateTextures(); m_pDevice->m_dwRuntimeFlags &= ~D3DRT_NEED_TEXTURE_UPDATE; } UINT NumVertices = m_CurNumberOfSprites * 4; LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2 pData; pData = (LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2) GetHalBufferPointer(D3DDP2OP_DRAWINDEXEDPRIMITIVE2, sizeof(*pData)); pData->primType = D3DPT_TRIANGLELIST; pData->BaseVertexOffset = m_pCurrentTLStream->GetPrimitiveBase(); pData->MinIndex = 0; pData->NumVertices = NumVertices; pData->StartIndexOffset = m_pCurrentIndexStream->GetPrimitiveBase(); pData->PrimitiveCount = m_CurNumberOfSprites * 2; m_pCurrentIndexStream->SkipVertices(m_CurNumberOfSprites * 6); m_pCurrentTLStream->SkipVertices(NumVertices); m_CurNumberOfSprites = 0; } SetWithinPrimitive(FALSE); } ///////////////////////////////////////////////////////////////////////////// // // // CD3DDDIDX8TL // // // ///////////////////////////////////////////////////////////////////////////// CD3DDDIDX8TL::CD3DDDIDX8TL() { m_ddiType = D3DDDITYPE_DX8TL; m_dwInterfaceNumber = 4; } //----------------------------------------------------------------------------- CD3DDDIDX8TL::~CD3DDDIDX8TL() { return; } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8TL::CreateVertexShader" void CD3DDDIDX8TL::CreateVertexShader(CONST DWORD* pdwDeclaration, DWORD dwDeclSize, CONST DWORD* pdwFunction, DWORD dwCodeSize, DWORD dwHandle, BOOL bLegacyFVF) { FlushStates(); LPD3DHAL_DP2CREATEVERTEXSHADER pData; pData = (LPD3DHAL_DP2CREATEVERTEXSHADER) GetHalBufferPointer(D3DDP2OP_CREATEVERTEXSHADER, sizeof(*pData) + dwDeclSize + dwCodeSize); pData->dwHandle = dwHandle; pData->dwDeclSize = dwDeclSize; pData->dwCodeSize = dwCodeSize; LPBYTE p = (LPBYTE)&pData[1]; memcpy(p, pdwDeclaration, dwDeclSize); if (pdwFunction) { p += dwDeclSize; memcpy(p, pdwFunction, dwCodeSize); } FlushStates(); } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8TL::DeleteVertexShader" void CD3DDDIDX8TL::DeleteVertexShader(DWORD dwHandle) { if (dwHandle == m_CurrentVertexShader) m_CurrentVertexShader = 0; LPD3DHAL_DP2VERTEXSHADER pData; pData = (LPD3DHAL_DP2VERTEXSHADER) GetHalBufferPointer(D3DDP2OP_DELETEVERTEXSHADER, sizeof(*pData)); pData->dwHandle = dwHandle; } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8TL::SetVertexShaderConstant" void CD3DDDIDX8TL::SetVertexShaderConstant(DWORD dwRegister, CONST VOID* data, DWORD count) { const DWORD size = count << 4; LPD3DHAL_DP2SETVERTEXSHADERCONST pData; pData = (LPD3DHAL_DP2SETVERTEXSHADERCONST) GetHalBufferPointer(D3DDP2OP_SETVERTEXSHADERCONST, sizeof(*pData) + size); pData->dwRegister = dwRegister; pData->dwCount = count; memcpy(pData+1, data, size); } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8TL::MultiplyTransform" void CD3DDDIDX8TL::MultiplyTransform(D3DTRANSFORMSTATETYPE state, CONST D3DMATRIX* lpMat) { // Send down the state and the matrix LPD3DHAL_DP2MULTIPLYTRANSFORM pData; pData = (LPD3DHAL_DP2MULTIPLYTRANSFORM) GetHalBufferPointer(D3DDP2OP_MULTIPLYTRANSFORM, sizeof(*pData)); pData->xfrmType = state; pData->matrix = *lpMat; } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8TL::SetTransform" void CD3DDDIDX8TL::SetTransform(D3DTRANSFORMSTATETYPE state, CONST D3DMATRIX* lpMat) { // Send down the state and the matrix LPD3DHAL_DP2SETTRANSFORM pData; pData = (LPD3DHAL_DP2SETTRANSFORM) GetHalBufferPointer(D3DDP2OP_SETTRANSFORM, sizeof(*pData)); pData->xfrmType = state; pData->matrix = *lpMat; } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8TL::SetViewport" void CD3DDDIDX8TL::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; } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8TL::SetMaterial" void CD3DDDIDX8TL::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 "CD3DDDIDX8TL::SetLight" void CD3DDDIDX8TL::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 UNALIGNED64 * p = (D3DLIGHT8 UNALIGNED64 *)((LPBYTE)pData + sizeof(D3DHAL_DP2SETLIGHT)); *p = *pLight; } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8TL::CreateLight" void CD3DDDIDX8TL::CreateLight(DWORD dwLightIndex) { LPD3DHAL_DP2CREATELIGHT pData; pData = (LPD3DHAL_DP2CREATELIGHT)GetHalBufferPointer(D3DDP2OP_CREATELIGHT, sizeof(*pData)); pData->dwIndex = dwLightIndex; } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8TL::LightEnable" void CD3DDDIDX8TL::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 "CD3DDDIDX8TL::SetClipPlane" void CD3DDDIDX8TL::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 "CD3DDDIDX8::ClearBatch" void CD3DDDIDX8::ClearBatch(BOOL bWithinPrimitive) { // Reset command buffer lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)lpvDP2Commands; dwDP2CommandLength = 0; dp2data.dwCommandOffset = 0; dp2data.dwCommandLength = 0; bDP2CurrCmdOP = 0; } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::FlushStates" void CD3DDDIDX8::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(); // Batch currently set VB streams CDDIStream* pStream = m_pDDIStream; for (UINT i=0; i < __NUMSTREAMS; i++) { if (pStream->m_pStream) { CVStream* p = static_cast(pStream->m_pStream); CVertexBuffer* pVB = p->m_pVB; if (pVB) pVB->Batch(); } pStream++; } // Now pStream points to the index stream if (pStream->m_pStream) { CVIndexStream* p = static_cast(pStream->m_pStream); CIndexBuffer* pVB = p->m_pVBI; if (pVB) pVB->Batch(); } // Save since it will get overwritten by ddrval after DDI call DWORD dwVertexSize = dp2data.dwVertexSize; 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; // 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. } // 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 "CD3DDDIDX8::ProcessPointSprites" void CD3DDDIDX8::PickProcessPrimitive() { D3DFE_PROCESSVERTICES* pv = static_cast(m_pDevice)->m_pv; if (pv->dwDeviceFlags & D3DDEV_DOPOINTSPRITEEMULATION) { m_pfnProcessPrimitive = ProcessPointSprites; } else if (pv->dwDeviceFlags & D3DDEV_TRANSFORMEDFVF) { m_pfnProcessPrimitive = static_cast(ProcessPrimitiveT); m_pfnProcessIndexedPrimitive = static_cast(ProcessIndexedPrimitiveT); } else if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP) { m_pfnProcessPrimitive = static_cast(ProcessPrimitive); m_pfnProcessIndexedPrimitive = static_cast(ProcessIndexedPrimitive); } else { m_pfnProcessPrimitive = static_cast(ProcessPrimitiveC); m_pfnProcessIndexedPrimitive = static_cast(ProcessIndexedPrimitiveC); } } //----------------------------------------------------------------------------- // Processes non-indexed primitives with untransformed vertices and without // clipping // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::ProcessPrimitive" void CD3DDDIDX8::ProcessPrimitive(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW); CD3DHal* pDevice = static_cast(m_pDevice); if (pDevice->dwFEFlags & D3DFE_FRONTEND_DIRTY) DoUpdateState(pDevice); pv->lpvOut = StartPrimTL(pv, pv->dwNumVertices * pv->dwOutputSize, TRUE); HRESULT ret = pv->pGeometryFuncs->ProcessVertices(pv); if (ret != D3D_OK) { SetWithinPrimitive(FALSE); m_pCurrentTLStream->Unlock(); D3D_THROW(ret, "Error in PSGP"); } DrawPrim(pv); SetWithinPrimitive(FALSE); m_pCurrentTLStream->Unlock(); } //----------------------------------------------------------------------------- // Processes non-indexed primitives with untransformed vertices and with // clipping // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::ProcessPrimitiveC" void CD3DDDIDX8::ProcessPrimitiveC(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW); CD3DHal* pDevice = static_cast(m_pDevice); // Update lighting and related flags if (pDevice->dwFEFlags & D3DFE_FRONTEND_DIRTY) DoUpdateState(pDevice); PrepareForClipping(pv, 0); pv->lpvOut = StartPrimTL(pv, pv->dwNumVertices * pv->dwOutputSize, NeverReadFromTLBuffer(pv)); // When a triangle strip is clipped, we draw indexed primitives // sometimes. This is why we need to initialize the index stream m_BaseVertexIndex = m_pCurrentTLStream->GetPrimitiveBase(); m_pCurrentIndexStream = m_pIndexStream; HRESULT ret; if (pv->primType == D3DPT_POINTLIST) { // When all points are clipped by X or Y planes we do not throw // them away, because they could have point size and be visible ret = D3D_OK; DWORD clipIntersection = pv->pGeometryFuncs->ProcessVertices(pv); clipIntersection &= ~(D3DCS_LEFT | D3DCS_RIGHT | D3DCS_TOP | D3DCS_BOTTOM | __D3DCLIPGB_ALL); if (!clipIntersection) { // There are some vertices inside the screen if (pv->dwClipUnion == 0) DrawPrim(pv); else ret = ProcessClippedPointSprites(pv); } } else { ret = pv->pGeometryFuncs->ProcessPrimitive(pv); } if (ret != D3D_OK) { SetWithinPrimitive(FALSE); m_pCurrentTLStream->Unlock(); D3D_THROW(ret, "Error in PSGP"); } SetWithinPrimitive(FALSE); m_pCurrentTLStream->Unlock(); UpdateClipStatus(pDevice); } //----------------------------------------------------------------------------- // Processes non-indexed primitives with transformed vertices with clipping // // Only transformed vertices generated by ProcessVertices call are allowed here // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::ProcessPrimitiveT" void CD3DDDIDX8::ProcessPrimitiveT(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW); // Clipping must be enabled when we are here DXGASSERT((pv->dwDeviceFlags & D3DDEV_DONOTCLIP) == 0); BOOL bNoClipping = FALSE; pv->dwOutputSize = m_pDevice->m_pStream[0].m_dwStride; // We need to do special processing for point sprites - they should not be // clipped as points without size. if (m_pDevice->m_dwRuntimeFlags & D3DRT_POINTSIZEPRESENT && pv->primType == D3DPT_POINTLIST) { // This function is called only if a device supports point sprites. // Otherwise DrawPoints() function should be called. DXGASSERT((pv->dwDeviceFlags & D3DDEV_DOPOINTSPRITEEMULATION) == 0); PrepareForClipping(pv, StartVertex); if (!(pv->dwDeviceFlags & D3DDEV_VBPROCVER)) { // Set emulation flag, because we want to compute clipping code as // for point sprites pv->dwDeviceFlags |= D3DDEV_DOPOINTSPRITEEMULATION; // Compute clip codes, because there was no ProcessVertices DWORD clip_intersect = D3DFE_GenClipFlags(pv); UpdateClipStatus(static_cast(m_pDevice)); pv->dwDeviceFlags &= ~D3DDEV_DOPOINTSPRITEEMULATION; if (clip_intersect) { return; } } // There are some vertices inside the screen. We need to do clipping if // a result of ProcessVertices is used as input (clip union is unknown) // or clipping is needed based on clip union and guard band flags. if (pv->dwDeviceFlags & D3DDEV_VBPROCVER || CheckIfNeedClipping(pv)) { // Set emulation flag, because clipped points should be expanded, // not regected. We will clip point sprites by viewport during // the expansion. pv->dwDeviceFlags |= D3DDEV_DOPOINTSPRITEEMULATION; // This will prevent computing clip codes second time. pv->dwDeviceFlags |= D3DDEV_VBPROCVER | D3DDEV_DONOTCOMPUTECLIPCODES; // Now we can call a function which will take care of point sprite // expansion, clipping, culling mode etc. ProcessPointSprites(pv, StartVertex); pv->dwDeviceFlags &= ~(D3DDEV_DOPOINTSPRITEEMULATION | D3DDEV_VBPROCVER | D3DDEV_DONOTCOMPUTECLIPCODES); return; } // We are here when all point centres are inside guard band. We can // draw them as points without clipping, because device supports point // sprites. bNoClipping = TRUE; } 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, &m_pDevice->m_pStream[0], StartVertex); if (bNoClipping) { DrawPrim(pv); goto l_exit; } PrepareForClipping(pv, StartVertex); CD3DHal* pDevice = static_cast(m_pDevice); pv->dwVIDOut = pv->dwVIDIn; pv->dwIndexOffset = 0; pv->lpvOut = pv->position.lpvData; 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; } // When a triangle strip is clipped, we draw indexed primitives // sometimes. m_BaseVertexIndex = 0; HRESULT ret = pDevice->GeometryFuncsGuaranteed->DoDrawPrimitive(pv); if (ret != D3D_OK) throw ret; l_exit: pv->dwFlags &= ~D3DPV_TLVCLIP; SetWithinPrimitive(FALSE); if (m_pDevice->m_dwRuntimeFlags & D3DRT_USERMEMPRIMITIVE) { m_pCurrentTLStream->Unlock(); } else { // If DDI vertex stream has been set to the internal stream during // clipping, we need to restore the original stream if (m_pDDIStream[0].m_pBuf != m_pDevice->m_pStream[0].m_pVB) { m_pDevice->m_dwStreamDirty |= 1; m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams() } } pv->dwFlags &= ~D3DPV_TLVCLIP; } //----------------------------------------------------------------------------- // Processes indexed primitives with untransformed vertices and without // clipping // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::ProcessIndexedPrimitive" void CD3DDDIDX8::ProcessIndexedPrimitive(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW); CD3DHal* pDevice = static_cast(m_pDevice); // Update lighting and related flags if (pDevice->dwFEFlags & D3DFE_FRONTEND_DIRTY) DoUpdateState(pDevice); pv->lpvOut = StartPrimTL(pv, pv->dwNumVertices * pv->dwOutputSize, TRUE); HRESULT ret = pv->pGeometryFuncs->ProcessVertices(pv); if (ret != D3D_OK) { SetWithinPrimitive(FALSE); m_pCurrentTLStream->Unlock(); D3D_THROW(ret, "Error in PSGP"); } if (pDevice->m_pIndexStream->m_pVBI) StartIndexPrimVB(pDevice->m_pIndexStream, m_StartIndex, pv->dwIndexSize); else m_pCurrentIndexStream = m_pIndexStream; // Let the driver map indices to be relative to the start of // the processed vertices m_BaseVertexIndex = m_pCurrentTLStream->GetPrimitiveBase() - m_MinVertexIndex * pv->dwOutputSize; DrawIndexPrim(pv); m_pCurrentTLStream->SkipVertices(pv->dwNumVertices); SetWithinPrimitive(FALSE); m_pCurrentTLStream->Unlock(); } //----------------------------------------------------------------------------- // Processes indexed primitives with untransformed vertices and with // clipping // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::ProcessIndexedPrimitiveC" void CD3DDDIDX8::ProcessIndexedPrimitiveC(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) != D3DFVF_XYZRHW); CD3DHal* pDevice = static_cast(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); PrepareForClipping(pv, 0); pv->lpvOut = StartPrimTL(pv, pv->dwNumVertices * pv->dwOutputSize, FALSE); m_BaseVertexIndex = m_pCurrentTLStream->GetPrimitiveBase() - m_MinVertexIndex * pv->dwOutputSize; pv->dwIndexOffset = m_MinVertexIndex; // Needed for clipping m_pCurrentIndexStream = m_pIndexStream; this->dwDP2Flags &= ~D3DDDI_INDEXEDPRIMDRAWN; m_pCurrentTLStream->AddVertices(pv->dwNumVertices); DWORD NumVertices = pv->dwNumVertices; HRESULT ret = pv->pGeometryFuncs->ProcessIndexedPrimitive(pv); if (this->dwDP2Flags & D3DDDI_INDEXEDPRIMDRAWN) m_pCurrentTLStream->MovePrimitiveBase(NumVertices); else m_pCurrentTLStream->SubVertices(NumVertices); SetWithinPrimitive(FALSE); m_pCurrentTLStream->Unlock(); UpdateClipStatus(pDevice); if (ret != D3D_OK) { D3D_THROW(ret, "Error in PSGP"); } } //----------------------------------------------------------------------------- // Processes indexed primitives with transformed vertices and with clipping // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::ProcessIndexedPrimitiveT" void CD3DDDIDX8::ProcessIndexedPrimitiveT(D3DFE_PROCESSVERTICES* pv, UINT StartVertex) { DXGASSERT((pv->dwVIDIn & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW); // Clipping must be enabled when we are here DXGASSERT((pv->dwDeviceFlags & D3DDEV_DONOTCLIP) == 0); CD3DHal* pDevice = static_cast(m_pDevice); pv->dwOutputSize = m_pDevice->m_pStream[0].m_dwStride; 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); // We need to adjust m_BaseVertexIndex, bacause we do not want to // re-compute indices for the new vertex base m_BaseVertexIndex = m_pCurrentTLStream->GetPrimitiveBase() - m_MinVertexIndex * pv->dwOutputSize; m_pCurrentTLStream->AddVertices(pv->dwNumVertices); // During clipping we need to adjust indices by m_MinVertexIndex pv->dwIndexOffset = m_MinVertexIndex; pv->lpwIndices = (WORD*)(pDevice->m_pIndexStream->Data()); } else { StartPrimVB(pv, &m_pDevice->m_pStream[0], StartVertex); m_BaseVertexIndex = pDevice->m_pIndexStream->m_dwBaseIndex * pv->dwOutputSize; pv->dwIndexOffset = m_MinVertexIndex; // For clipping pv->lpwIndices = (WORD*)(pDevice->m_pIndexStream->Data() + m_StartIndex * pDevice->m_pIndexStream->m_dwStride); } PrepareForClipping(pv, StartVertex); 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->dwVIDOut = pv->dwVIDIn; pv->lpvOut = pv->position.lpvData; m_pCurrentIndexStream = m_pIndexStream; HRESULT ret; ret = pDevice->GeometryFuncsGuaranteed->DoDrawIndexedPrimitive(pv); if (ret != D3D_OK) throw ret; l_exit: SetWithinPrimitive(FALSE); if (m_pDevice->m_dwRuntimeFlags & D3DRT_USERMEMPRIMITIVE) { m_pCurrentTLStream->Unlock(); m_pCurrentTLStream->MovePrimitiveBase(pv->dwNumVertices); } else { // If DDI vertex stream has been set to the internal stream during // clipping, we need to restore the original stream if (m_pDDIStream[0].m_pBuf != m_pDevice->m_pStream[0].m_pVB) { m_pDevice->m_dwStreamDirty |= 1; m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams() } // If DDI index stream has been set to the internal stream during // clipping, we need to restore the original stream if (m_pDDIStream[__NUMSTREAMS].m_pBuf != m_pDevice->m_pIndexStream->m_pVBI) { m_pDevice->m_dwStreamDirty |= (1 << __NUMSTREAMS); m_pDevice->m_dwRuntimeFlags |= D3DRT_NEED_VB_UPDATE; // Need to call UpdateDirtyStreams() } } pv->dwFlags &= ~D3DPV_TLVCLIP; } //----------------------------------------------------------------------------- #if DBG #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::ValidateCommand" void CD3DDDIDX8::ValidateCommand(LPD3DHAL_DP2COMMAND lpCmd) { CD3DHal* pDevice = static_cast(m_pDevice); D3DFE_PROCESSVERTICES* pv = static_cast(m_pDevice)->m_pv; if (!(pDevice->m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING)) return; DWORD dwVertexSize = pv->dwOutputSize; BOOL bNeedUnlock = FALSE; UINT count; BYTE* pVertices; CTLStream* pStream = (CTLStream*)m_pDDIStream[0].m_pStream; if (pStream->m_pVB) if (pStream->m_pVB->IsLocked()) pVertices = pStream->m_pData; else { pVertices = pStream->Lock(pStream->m_pVB->GetBufferDesc()->Size, this); bNeedUnlock = TRUE; } else // User memory vertices pVertices = (LPBYTE)(dp2data.lpVertices); switch (lpCmd->bCommand) { case D3DDP2OP_DRAWPRIMITIVE: { LPD3DHAL_DP2DRAWPRIMITIVE pData = (LPD3DHAL_DP2DRAWPRIMITIVE)(lpCmd+1); count = GETVERTEXCOUNT(pData->primType, pData->PrimitiveCount); pVertices += pData->VStart * dwVertexSize; for (WORD i = 0; i < count; i++) { ValidateVertex((LPDWORD)(pVertices + i * dwVertexSize)); } } break; case D3DDP2OP_DRAWPRIMITIVE2: { LPD3DHAL_DP2DRAWPRIMITIVE2 pData = (LPD3DHAL_DP2DRAWPRIMITIVE2)(lpCmd+1); count = GETVERTEXCOUNT(pData->primType, pData->PrimitiveCount); pVertices += pData->FirstVertexOffset; for (WORD i = 0; i < count; i++) { ValidateVertex((LPDWORD)(pVertices + i * dwVertexSize)); } } break; case D3DDP2OP_DRAWINDEXEDPRIMITIVE: case D3DDP2OP_DRAWINDEXEDPRIMITIVE2: { BYTE* pIndices; BOOL bNeedUnlock = FALSE; CTLIndexStream* pStream = (CTLIndexStream*)m_pDDIStream[__NUMSTREAMS].m_pStream; if (pStream->m_pVBI->IsLocked()) pIndices = pStream->m_pData; else { pIndices = pStream->Lock(pStream->m_pVBI->GetBufferDesc()->Size, this); bNeedUnlock = TRUE; } UINT MaxIndex; UINT MinIndex; if (lpCmd->bCommand == D3DDP2OP_DRAWINDEXEDPRIMITIVE) { LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE pData = (LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE)(lpCmd+1); pIndices += pData->StartIndex * pv->dwIndexSize; pVertices += pData->BaseVertexIndex * dwVertexSize; MaxIndex = pData->MinIndex + pData->NumVertices - 1; count = GETVERTEXCOUNT(pData->primType, pData->PrimitiveCount); MinIndex = pData->MinIndex; } else { LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2 pData = (LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2)(lpCmd+1); pIndices += pData->StartIndexOffset; pVertices += pData->BaseVertexOffset; MaxIndex = pData->MinIndex + pData->NumVertices - 1; count = GETVERTEXCOUNT(pData->primType, pData->PrimitiveCount); MinIndex = pData->MinIndex; } for (WORD i = 0; i < count; i++) { DWORD index; if (pv->dwIndexSize == 4) index = *(DWORD*)(pIndices + i * 4); else index = *(WORD*)(pIndices + i * 2); if (index < MinIndex || index > MaxIndex) { D3D_THROW_FAIL("Invalid index in the index stream"); } BYTE* pVertex = &pVertices[index]; if (pVertex < pVertices || pVertex > pVertices + dwVertexSize * MaxIndex) { D3D_THROW_FAIL("Bad vertex address"); } ValidateVertex((LPDWORD)(pVertices + index * dwVertexSize)); } if (bNeedUnlock) pStream->Unlock(); } break; case D3DDP2OP_CLIPPEDTRIANGLEFAN: if (bNeedUnlock) pStream->Unlock(); CD3DDDIDX6::ValidateCommand(lpCmd); return; case D3DDP2OP_DRAWRECTPATCH: case D3DDP2OP_DRAWTRIPATCH: return; default: D3D_THROW_FAIL("Invalid DX8 drawing command in DP2 stream"); } if (bNeedUnlock) pStream->Unlock(); } #endif //----------------------------------------------------------------------------- // Volume Blt // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::VolBlt" void CD3DDDIDX8::VolBlt(CBaseTexture *lpDst, CBaseTexture* lpSrc, DWORD dwDestX, DWORD dwDestY, DWORD dwDestZ, D3DBOX *pBox) { if (bDP2CurrCmdOP == D3DDP2OP_VOLUMEBLT) { // Last instruction is a tex blt, append this one to it if (dwDP2CommandLength + sizeof(D3DHAL_DP2VOLUMEBLT) <= dwDP2CommandBufSize) { LPD3DHAL_DP2VOLUMEBLT lpVolBlt = (LPD3DHAL_DP2VOLUMEBLT)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt; lpVolBlt->dwDDDestSurface = lpDst == NULL ? 0 : lpDst->DriverAccessibleDrawPrimHandle(); lpVolBlt->dwDDSrcSurface = lpSrc->BaseDrawPrimHandle(); lpVolBlt->dwDestX = dwDestX; lpVolBlt->dwDestY = dwDestY; lpVolBlt->dwDestZ = dwDestZ; lpVolBlt->srcBox = *pBox; lpVolBlt->dwFlags = 0; dwDP2CommandLength += sizeof(D3DHAL_DP2VOLUMEBLT); D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); // For the source, we want to call BatchBase since // we want to batch the backing (or sysmem) texture // rather than the promoted one. lpSrc->BatchBase(); if(lpDst != 0) { lpDst->Batch(); } return; } } // Check for space if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2VOLUMEBLT) > dwDP2CommandBufSize) { FlushStates(); } // Add new instruction lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->bCommand = D3DDP2OP_VOLUMEBLT; bDP2CurrCmdOP = D3DDP2OP_VOLUMEBLT; lpDP2CurrCommand->bReserved = 0; lpDP2CurrCommand->wStateCount = 1; wDP2CurrCmdCnt = 1; D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); // Add texture blt data LPD3DHAL_DP2VOLUMEBLT lpVolBlt = (LPD3DHAL_DP2VOLUMEBLT)(lpDP2CurrCommand + 1); lpVolBlt->dwDDDestSurface = lpDst == NULL ? 0 : lpDst->DriverAccessibleDrawPrimHandle(); lpVolBlt->dwDDSrcSurface = lpSrc->BaseDrawPrimHandle(); lpVolBlt->dwDestX = dwDestX; lpVolBlt->dwDestY = dwDestY; lpVolBlt->dwDestZ = dwDestZ; lpVolBlt->srcBox = *pBox; lpVolBlt->dwFlags = 0; dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2VOLUMEBLT); // For the source, we want to call BatchBase since // we want to batch the backing (or sysmem) texture // rather than the promoted one. lpSrc->BatchBase(); if(lpDst != 0) { lpDst->Batch(); } } //----------------------------------------------------------------------------- // Buffer Blt // #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::BufBlt" void CD3DDDIDX8::BufBlt(CBuffer *lpDst, CBuffer* lpSrc, DWORD dwOffset, D3DRANGE* pRange) { if (bDP2CurrCmdOP == D3DDP2OP_BUFFERBLT) { // Last instruction is a tex blt, append this one to it if (dwDP2CommandLength + sizeof(D3DHAL_DP2BUFFERBLT) <= dwDP2CommandBufSize) { LPD3DHAL_DP2BUFFERBLT lpBufBlt = (LPD3DHAL_DP2BUFFERBLT)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->wStateCount = ++wDP2CurrCmdCnt; lpBufBlt->dwDDDestSurface = lpDst == NULL ? 0 : lpDst->DriverAccessibleDrawPrimHandle(); lpBufBlt->dwDDSrcSurface = lpSrc->BaseDrawPrimHandle(); lpBufBlt->dwOffset = dwOffset; lpBufBlt->rSrc = *pRange; lpBufBlt->dwFlags = 0; dwDP2CommandLength += sizeof(D3DHAL_DP2BUFFERBLT); D3D_INFO(6, "Modify Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); // For the source, we want to call BatchBase since // we want to batch the backing (or sysmem) texture // rather than the promoted one. lpSrc->BatchBase(); if(lpDst != 0) { lpDst->Batch(); } return; } } // Check for space if (dwDP2CommandLength + sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2BUFFERBLT) > dwDP2CommandBufSize) { FlushStates(); } // Add new instruction lpDP2CurrCommand = (LPD3DHAL_DP2COMMAND)((LPBYTE)lpvDP2Commands + dwDP2CommandLength + dp2data.dwCommandOffset); lpDP2CurrCommand->bCommand = D3DDP2OP_BUFFERBLT; bDP2CurrCmdOP = D3DDP2OP_BUFFERBLT; lpDP2CurrCommand->bReserved = 0; lpDP2CurrCommand->wStateCount = 1; wDP2CurrCmdCnt = 1; D3D_INFO(6, "Write Ins:%08lx", *(LPDWORD)lpDP2CurrCommand); // Add texture blt data LPD3DHAL_DP2BUFFERBLT lpBufBlt = (LPD3DHAL_DP2BUFFERBLT)(lpDP2CurrCommand + 1); lpBufBlt->dwDDDestSurface = lpDst == NULL ? 0 : lpDst->DriverAccessibleDrawPrimHandle(); lpBufBlt->dwDDSrcSurface = lpSrc->BaseDrawPrimHandle(); lpBufBlt->dwOffset = dwOffset; lpBufBlt->rSrc = *pRange; lpBufBlt->dwFlags = 0; dwDP2CommandLength += sizeof(D3DHAL_DP2COMMAND) + sizeof(D3DHAL_DP2BUFFERBLT); // For the source, we want to call BatchBase since // we want to batch the backing (or sysmem) texture // rather than the promoted one. lpSrc->BatchBase(); if(lpDst != 0) { lpDst->Batch(); } } //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DDDIDX8::GetMaxRenderState" // Note: This is a hack for DX8.1 release. The only renderstates that we added // in DX8.1 pertain to the NPATCHES features. At the time of DX8.1 release // there were no real drivers besides Reference that could support this feature. // We also know that the only can driver that does support the NPATCH feature // will support these renderstates (i.e. will be a DX8.1 driver. Hence it is // safe to assume that if any driver supports the D3DDEVCAPS_NPATCHES cap, then // it is a DX8.1 driver and understands the extra renderstates that were added // in DX8.1. D3DRENDERSTATETYPE CD3DDDIDX8::GetMaxRenderState() { const D3DCAPS8* pCaps = m_pDevice->GetD3DCaps(); if (pCaps->DevCaps & D3DDEVCAPS_NPATCHES) { return D3D_MAXRENDERSTATES; } else { return D3DRS_POSITIONORDER; } }