mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2741 lines
98 KiB
2741 lines
98 KiB
#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<CVertexBuffer*>(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<CIndexBuffer*>(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<CD3DHal*>(pDevice);
|
|
UINT nVer = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount);
|
|
pDev->ValidateDraw2(PrimitiveType, StartVertex, PrimitiveCount,
|
|
nVer, FALSE);
|
|
}
|
|
#endif // DBG
|
|
CD3DDDIDX8* pDDI = static_cast<CD3DDDIDX8*>(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<CD3DHal*>(pDevice);
|
|
pDev->ValidateDraw2(PrimitiveType, MinIndex + BaseVertexIndex,
|
|
PrimitiveCount, NumVertices, TRUE, StartIndex);
|
|
}
|
|
#endif // DBG
|
|
CD3DDDIDX8* pDDI = static_cast<CD3DDDIDX8*>(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<CBuffer*>(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<CBuffer*>(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<CBuffer*>(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<CBuffer*>(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<CD3DHal*>(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<CD3DHal*>(m_pDevice)->m_pv;
|
|
m_pCurrentIndexStream->Unlock();
|
|
m_pCurrentTLStream->Unlock();
|
|
if (m_CurNumberOfSprites)
|
|
{
|
|
if (m_pDDIStream[__NUMSTREAMS].m_pBuf != static_cast<CBuffer*>(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<CBuffer*>(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<CVStream*>(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<CVIndexStream*>(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<CD3DHal*>(m_pDevice)->m_pv;
|
|
if (pv->dwDeviceFlags & D3DDEV_DOPOINTSPRITEEMULATION)
|
|
{
|
|
m_pfnProcessPrimitive = ProcessPointSprites;
|
|
}
|
|
else
|
|
if (pv->dwDeviceFlags & D3DDEV_TRANSFORMEDFVF)
|
|
{
|
|
m_pfnProcessPrimitive =
|
|
static_cast<PFN_PROCESSPRIM>(ProcessPrimitiveT);
|
|
m_pfnProcessIndexedPrimitive =
|
|
static_cast<PFN_PROCESSPRIM>(ProcessIndexedPrimitiveT);
|
|
}
|
|
else
|
|
if (pv->dwDeviceFlags & D3DDEV_DONOTCLIP)
|
|
{
|
|
m_pfnProcessPrimitive =
|
|
static_cast<PFN_PROCESSPRIM>(ProcessPrimitive);
|
|
m_pfnProcessIndexedPrimitive =
|
|
static_cast<PFN_PROCESSPRIM>(ProcessIndexedPrimitive);
|
|
}
|
|
else
|
|
{
|
|
m_pfnProcessPrimitive =
|
|
static_cast<PFN_PROCESSPRIM>(ProcessPrimitiveC);
|
|
m_pfnProcessIndexedPrimitive =
|
|
static_cast<PFN_PROCESSPRIM>(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<CD3DHal*>(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<CD3DHal*>(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<CD3DHal*>(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<CD3DHal*>(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<CD3DHal*>(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<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);
|
|
|
|
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<CD3DHal*>(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<CD3DHal*>(m_pDevice);
|
|
D3DFE_PROCESSVERTICES* pv = static_cast<CD3DHal*>(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;
|
|
}
|
|
}
|