|
|
/*============================================================================
* * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved. * * File: vshader.cpp * Content: SetStreamSource and VertexShader * software implementation. * ****************************************************************************/
#include "pch.cpp"
#pragma hdrstop
#include "ibuffer.hpp"
#include "fe.h"
#include "ddibase.h"
#include "pvvid.h"
void __Transpose(D3DMATRIXI* m, D3DMATRIX* res) { res->_11 = m->_11; res->_12 = m->_21; res->_13 = m->_31; res->_14 = m->_41; res->_21 = m->_12; res->_22 = m->_22; res->_23 = m->_32; res->_24 = m->_42; res->_31 = m->_13; res->_32 = m->_23; res->_33 = m->_33; res->_34 = m->_43; res->_41 = m->_14; res->_42 = m->_24; res->_43 = m->_34; res->_44 = m->_44; } //-----------------------------------------------------------------------------
// Forward definitions
//
void CD3DHal_DrawPrimitive(CD3DBase* pBaseDevice, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount); void CD3DHal_DrawIndexedPrimitive(CD3DBase* pBaseDevice, D3DPRIMITIVETYPE PrimitiveType, UINT BaseIndex, UINT MinIndex, UINT NumVertices, UINT StartIndex, UINT PrimitiveCount); void CD3DHal_DrawNPatch(CD3DBase* pBaseDevice, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount); void CD3DHal_DrawIndexedNPatch(CD3DBase* pBaseDevice, D3DPRIMITIVETYPE PrimitiveType, UINT BaseIndex, UINT MinIndex, UINT NumVertices, UINT StartIndex, UINT PrimitiveCount); //-----------------------------------------------------------------------------
void __declspec(nothrow) CD3DHal::PickDrawPrimFn() { if (!(m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING)) { m_pfnDrawPrim = m_pDDI->GetDrawPrimFunction(); m_pfnDrawIndexedPrim = m_pDDI->GetDrawIndexedPrimFunction(); if (m_dwRuntimeFlags & D3DRT_DONPATCHCONVERSION) { m_pfnDrawPrimFromNPatch = m_pfnDrawPrim; m_pfnDrawIndexedPrimFromNPatch = m_pfnDrawIndexedPrim; m_pfnDrawPrim = CD3DHal_DrawNPatch; m_pfnDrawIndexedPrim = CD3DHal_DrawIndexedNPatch; } } else { DWORD dwDeviceFlags = m_pv->dwDeviceFlags; BOOL bCallDriver; if (Enum()->GetAppSdkVersion() == D3D_SDK_VERSION_DX8) { bCallDriver = dwDeviceFlags & D3DDEV_TRANSFORMEDFVF && (dwDeviceFlags & D3DDEV_DONOTCLIP || !(dwDeviceFlags & D3DDEV_VBPROCVER)); } else { bCallDriver = dwDeviceFlags & D3DDEV_TRANSFORMEDFVF && dwDeviceFlags & D3DDEV_DONOTCLIP; } if (bCallDriver) { m_pfnDrawPrim = m_pDDI->GetDrawPrimFunction(); m_pfnDrawIndexedPrim = m_pDDI->GetDrawIndexedPrimFunction(); } else { m_pfnDrawPrim = CD3DHal_DrawPrimitive; m_pfnDrawIndexedPrim = CD3DHal_DrawIndexedPrimitive; } } } //-----------------------------------------------------------------------------
// Checks if we can call driver directly to draw the current primitive
//
inline BOOL CanCallDriver(CD3DHal* pDev, D3DPRIMITIVETYPE PrimType) { DWORD dwDeviceFlags = pDev->m_pv->dwDeviceFlags; if (PrimType != D3DPT_POINTLIST) return dwDeviceFlags & D3DDEV_TRANSFORMEDFVF && (dwDeviceFlags & D3DDEV_DONOTCLIP || pDev->Enum()->GetAppSdkVersion() == D3D_SDK_VERSION_DX8); else // This function could be called from DrawPointsI, which could be
// called from other Draw() function than DrawPrimitiveUP, so we need
// to check for D3DDEV_VBPROCVER. We cannot pass vertices, which are
// result of ProcessVertices(), to the driver directly
return dwDeviceFlags & D3DDEV_TRANSFORMEDFVF && !(pDev->m_dwRuntimeFlags & D3DRT_DOPOINTSPRITEEMULATION) && (dwDeviceFlags & D3DDEV_DONOTCLIP || (pDev->Enum()->GetAppSdkVersion() == D3D_SDK_VERSION_DX8 && !(dwDeviceFlags & D3DDEV_VBPROCVER))); } //-----------------------------------------------------------------------------
// API calls
//-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::SetStreamSourceI"
void CD3DHal::SetStreamSourceI(CVStream* pStream) { if (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) { CVertexBuffer * pVB = pStream->m_pVB; m_pv->dwDeviceFlags &= ~D3DDEV_VBPROCVER; DWORD dwFVF = pVB->GetFVF(); if (pVB->GetClipCodes() != NULL) { // This vertex buffer is the output of ProcessVertices
DXGASSERT(FVF_TRANSFORMED(dwFVF)); m_pv->dwDeviceFlags |= D3DDEV_VBPROCVER; } if (D3DVSD_ISLEGACY(m_dwCurrentShaderHandle)) { SetupStrides(m_pv, m_pStream[0].m_dwStride); } } PickDrawPrimFn(); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::SetIndicesI"
void CD3DHal::SetIndicesI(CVIndexStream* pStream) { } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::CreateVertexShaderI"
void CD3DHal::CreateVertexShaderI(CONST DWORD* pdwDeclaration, DWORD dwDeclSize, CONST DWORD* pdwFunction, DWORD dwCodeSize, DWORD dwHandle) { BOOL bIsCheckedBuild = #if DBG
TRUE; #else
FALSE; #endif
CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(dwHandle); if (pShader->m_dwFlags & CVShader::SOFTWARE) {
// Build the array of all vertex elements used in the shader by going
// through all streams and elements inside each stream.
CVDeclaration* pDecl = &pShader->m_Declaration; CVStreamDecl* pStream = pShader->m_Declaration.m_pActiveStreams; // This is the array we build
CVElement* pVerElem = pShader->m_Declaration.m_VertexElements; pDecl->m_dwNumElements = 0; while (pStream) { for (DWORD i=0; i < pStream->m_dwNumElements; i++) { if (pDecl->m_dwNumElements >= __NUMELEMENTS) { D3D_THROW_FAIL("Declaration is using too many elements"); } *pVerElem = pStream->m_Elements[i]; pVerElem->m_dwStreamIndex = pStream->m_dwStreamIndex; pVerElem++; pDecl->m_dwNumElements++; } pStream = (CVStreamDecl*)pStream->m_pNext; }
if (pdwFunction != NULL) { // compute adjusted function pointer depending on FREE/CHECKED and PSGP
LPDWORD pdwFunctionAdj = pShader->m_pStrippedFuncCode; if ( bIsCheckedBuild && ((LPVOID)m_pv->pGeometryFuncs == (LPVOID)GeometryFuncsGuaranteed) ) // !PSGP
{ pdwFunctionAdj = pShader->m_pOrgFuncCode; } // Microsoft shader is always created.
// It is used for validation and to compute the output FVF in case
// when PSGP is present
HRESULT hr; hr = GeometryFuncsGuaranteed->CreateShader( pDecl->m_VertexElements, pDecl->m_dwNumElements, pdwFunctionAdj, 0, (CPSGPShader**)&pShader->m_pCode); if(FAILED(hr)) { D3D_THROW_FAIL("Failed to create vertex shader code"); } // When device driver can not handle separate fog value in the FVF,
// we should use specular alpha as the fog factor
if (pShader->m_pCode->m_dwOutFVF & D3DFVF_FOG && !(GetD3DCaps()->PrimitiveMiscCaps & D3DPMISCCAPS_FOGINFVF)) { pShader->m_pCode->m_dwOutFVF &= ~D3DFVF_FOG; // Assume that texture coordinates follow fog value
// No need to adjust offsets when specular is already present
if (pShader->m_pCode->m_dwOutFVF & D3DFVF_SPECULAR) { pShader->m_pCode->m_dwOutVerSize -= 4; pShader->m_pCode->m_dwTextureOffset -= 4; } pShader->m_pCode->m_dwOutFVF |= D3DFVF_SPECULAR; } // Clear texture format bits if device can handle only 2 floats per
// texture coordinate
if (m_dwRuntimeFlags & D3DRT_ONLY2FLOATSPERTEXTURE && pShader->m_pCode->m_dwOutFVF & 0xFFFF0000) { CVShaderCode * pCode = pShader->m_pCode; pCode->m_dwOutFVF &= 0x0000FFFF; pCode->m_dwOutVerSize = ComputeVertexSizeFVF(pCode->m_dwOutFVF); for (DWORD i=0; i < pCode->m_nOutTexCoord; i++) { pCode->m_dwOutTexCoordSize[i] = 2 * 4; } } if ((LPVOID)m_pv->pGeometryFuncs != (LPVOID)GeometryFuncsGuaranteed) { DWORD dwOutputFVF = pShader->m_pCode->m_dwOutFVF; CVShaderCode* pCodeMs = pShader->m_pCode; // Now we can create PSGP shader
hr = m_pv->pGeometryFuncs->CreateShader(pDecl->m_VertexElements, pDecl->m_dwNumElements, pdwFunctionAdj, dwOutputFVF, (CPSGPShader**)&pShader->m_pCode); if(FAILED(hr)) { delete pCodeMs; D3D_THROW_FAIL("Failed to create vertex shader code"); } // Copy pre-computed data from Microsoft's shader to the PSGP
CPSGPShader * pCode = pShader->m_pCode; CPSGPShader * pMsShader = pCodeMs; pCode->m_dwOutRegs = pMsShader->m_dwOutRegs; pCode->m_dwOutFVF = pMsShader->m_dwOutFVF; pCode->m_dwPointSizeOffset = pMsShader->m_dwPointSizeOffset; pCode->m_dwDiffuseOffset = pMsShader->m_dwDiffuseOffset; pCode->m_dwSpecularOffset = pMsShader->m_dwSpecularOffset; pCode->m_dwFogOffset = pMsShader->m_dwFogOffset; pCode->m_dwTextureOffset = pMsShader->m_dwTextureOffset; pCode->m_nOutTexCoord = pMsShader->m_nOutTexCoord; pCode->m_dwOutVerSize = pMsShader->m_dwOutVerSize; for (DWORD i=0; i < pCode->m_nOutTexCoord; i++) { pCode->m_dwOutTexCoordSize[i] = pMsShader->m_dwOutTexCoordSize[i]; } // Microsoft shader is not needed any more
delete pCodeMs; } } } else { if ( bIsCheckedBuild && (GetDeviceType() != D3DDEVTYPE_HAL ) ) { // pass non-stripped version
m_pDDI->CreateVertexShader( pdwDeclaration, dwDeclSize, pShader->m_pOrgFuncCode, pShader->m_OrgFuncCodeSize, dwHandle, pShader->m_Declaration.m_bLegacyFVF); } else { // pass stripped version
m_pDDI->CreateVertexShader( pdwDeclaration, dwDeclSize, pShader->m_pStrippedFuncCode, pShader->m_StrippedFuncCodeSize, dwHandle, pShader->m_Declaration.m_bLegacyFVF); } } DebugStateChanged( D3DDM_SC_VSMODIFYSHADERS ); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::SetVertexShaderI"
void CD3DHal::SetVertexShaderI(DWORD dwHandle) { #if DBG
// We need to validate shader handle here, because the shader could be
// deleted by user after creating a state block with the shader handle.
CheckVertexShaderHandle(dwHandle); #endif
CVConstantData* pConst = NULL; if (!D3DVSD_ISLEGACY(dwHandle)) { CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(dwHandle); pConst = pShader->m_Declaration.m_pConstants; } // Ignore redundant handle when we do not need to update constantes
if(pConst == NULL) { if(dwHandle == m_dwCurrentShaderHandle) return; } else { // Load constants
while (pConst) { HRESULT hr; hr = m_pv->pGeometryFuncs->LoadShaderConstants(pConst->m_dwAddress, pConst->m_dwCount, pConst->m_pData); if (FAILED(hr)) { D3D_THROW_FAIL("Failed to load vertex shader constants"); } pConst = (CVConstantData*)pConst->m_pNext; m_dwRuntimeFlags |= D3DRT_NEED_VSCONST_UPDATE; } }
ForceFVFRecompute(); // When we switch from FVF shaders to programmable we need to re-compute
// clipping planes, because they are transformed by different matrix
if (this->rstates[D3DRENDERSTATE_CLIPPLANEENABLE]) { this->dwFEFlags |= D3DFE_CLIPPLANES_DIRTY; }
m_dwCurrentShaderHandle = dwHandle; if (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) { m_dwRuntimeFlags &= ~D3DRT_POINTSIZEINVERTEX; m_dwRuntimeFlags |= D3DRT_SHADERDIRTY; m_pv->dwDeviceFlags &= ~D3DDEV_TRANSFORMEDFVF;
if (D3DVSD_ISLEGACY(dwHandle)) { if (dwHandle & D3DFVF_PSIZE) m_dwRuntimeFlags |= D3DRT_POINTSIZEINVERTEX;
m_pCurrentShader = NULL; m_pv->dwDeviceFlags &= ~(D3DDEV_STRIDE | D3DDEV_VERTEXSHADERS);
if (FVF_TRANSFORMED(dwHandle)) { if (!(m_dwRuntimeFlags & D3DRT_EXECUTESTATEMODE)) { m_pDDI->SetVertexShader(dwHandle); } m_pv->dwDeviceFlags |= D3DDEV_TRANSFORMEDFVF; }
m_pfnPrepareToDraw = PrepareToDrawLegacy; m_pv->dwVIDIn = dwHandle; SetupStrides(m_pv, m_pStream[0].m_dwStride); } else { CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(dwHandle); m_pCurrentShader = pShader; if(!(pShader->m_dwFlags & CVShader::FIXEDFUNCTION)) { // Programmable vertex shaders are used
m_pv->dwDeviceFlags |= D3DDEV_VERTEXSHADERS; m_pfnPrepareToDraw = PrepareToDrawVVM; if (m_pCurrentShader->m_pCode->m_dwOutFVF & D3DFVF_PSIZE) m_dwRuntimeFlags |= D3DRT_POINTSIZEINVERTEX;
// Pre-compute as much info as possible and keep it
// in the vertex descriptors. This information is constant
// unless shader is changed
CVDeclaration* pDecl = &m_pCurrentShader->m_Declaration; CVertexDesc* pVD = m_pv->VertexDesc; CVElement *pElem = pDecl->m_VertexElements; m_pv->dwNumUsedVertexDescs = pDecl->m_dwNumElements; for (DWORD i = pDecl->m_dwNumElements; i; i--) { pVD->pfnCopy = pElem->m_pfnCopy; pVD->dwRegister = pElem->m_dwRegister; pVD->dwVertexOffset = pElem->m_dwOffset; pVD->pStream = &m_pStream[pElem->m_dwStreamIndex]; pVD++; pElem++; } } else { // Fixed-function pipeline is used with declarations
// We draw primitives using strided code path
m_pv->dwDeviceFlags |= D3DDEV_STRIDE; m_pv->dwDeviceFlags &= ~D3DDEV_VERTEXSHADERS;
m_pfnPrepareToDraw = PrepareToDraw;
if (pShader->m_dwInputFVF & D3DFVF_PSIZE) m_dwRuntimeFlags |= D3DRT_POINTSIZEINVERTEX;
// Go through the elements in the current declaration and
// initialize vertex descriptors. They are used to quickly
// initialize strided data pointers.
CVDeclaration* pDecl = &m_pCurrentShader->m_Declaration; CVertexDesc* pVD = m_pv->VertexDesc; CVElement *pElem = pDecl->m_VertexElements; m_pv->dwNumUsedVertexDescs = pDecl->m_dwNumElements; for (DWORD i = pDecl->m_dwNumElements; i; i--) { pVD->pElement = &m_pv->elements[pElem->m_dwRegister]; pVD->pStream = &m_pStream[pElem->m_dwStreamIndex]; pVD->dwVertexOffset = pElem->m_dwOffset; pVD++; pElem++; } m_pv->dwVIDIn = pDecl->m_dwInputFVF; if (pDecl->m_dwInputFVF & D3DFVF_PSIZE) m_dwRuntimeFlags |= D3DRT_POINTSIZEINVERTEX; } HRESULT hr = m_pv->pGeometryFuncs->SetActiveShader(pShader->m_pCode); if (FAILED(hr)) { D3D_THROW_FAIL("Failed to set active vertex shader"); } } m_pDDI->PickProcessPrimitive(); } else { #if DBG
// For the validation we need to set the m_pCurrentShader even for
// hardware mode
m_pv->dwDeviceFlags &= ~D3DDEV_VERTEXSHADERS; if (D3DVSD_ISLEGACY(dwHandle)) { m_pCurrentShader = NULL; } else { m_pCurrentShader = (CVShader*)m_pVShaderArray->GetObject(dwHandle); if(!(m_pCurrentShader->m_dwFlags & CVShader::FIXEDFUNCTION)) { // Programmable pipeline is used
m_pv->dwDeviceFlags |= D3DDEV_VERTEXSHADERS; } } #endif
if (!(m_dwRuntimeFlags & D3DRT_EXECUTESTATEMODE)) { m_pDDI->SetVertexShaderHW(dwHandle); } } PickDrawPrimFn(); DebugStateChanged( D3DDM_SC_VSSETSHADER ); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::DeleteVertexShaderI"
void CD3DHal::DeleteVertexShaderI(DWORD dwHandle) { #if DBG
for(unsigned Handle = 0; Handle < m_pRTPatchValidationInfo->GetSize(); ++Handle) { if ((*m_pRTPatchValidationInfo)[Handle].m_pObj != 0) { if (static_cast<CRTPatchValidationInfo*>((*m_pRTPatchValidationInfo)[Handle].m_pObj)->m_ShaderHandle == dwHandle) { static_cast<CRTPatchValidationInfo*>((*m_pRTPatchValidationInfo)[Handle].m_pObj)->m_ShaderHandle = 0; D3D_INFO(0, "Found this vertex shader in a cached patch. Will invalidate the cached patch."); } } } #endif // DBG
if (dwHandle == m_dwCurrentShaderHandle) { m_pCurrentShader = NULL; m_dwCurrentShaderHandle = 0; } if (!D3DVSD_ISLEGACY(dwHandle)) { CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(dwHandle); #if DBG
if (pShader == NULL) { D3D_THROW(D3DERR_INVALIDCALL, "Invalid vertex shader handle"); } #endif
if (!(pShader->m_dwFlags & CVShader::SOFTWARE)) { m_pDDI->DeleteVertexShader(dwHandle); } } DebugStateChanged( D3DDM_SC_VSMODIFYSHADERS ); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::SetVertexShaderConstantI"
void CD3DHal::SetVertexShaderConstantI(DWORD Register, CONST VOID* pData, DWORD count) { HRESULT hr; if (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING || ((count + Register) <= D3DVS_CONSTREG_MAX_V1_1)) { // For software vertex processing we store constant registers in PSGP if
// possible
hr = m_pv->pGeometryFuncs->LoadShaderConstants(Register, count, const_cast<VOID*>(pData)); } else { if (Register >= D3DVS_CONSTREG_MAX_V1_1) { // When all modified registers are above software limit, we use Microsoft
// internal array
hr = GeometryFuncsGuaranteed->LoadShaderConstants(Register, count, const_cast<VOID*>(pData)); } else { // Part of constant data is stores in the PSGP array and part in the
// Microsoft's array
UINT FirstCount = D3DVS_CONSTREG_MAX_V1_1 - Register; hr = m_pv->pGeometryFuncs->LoadShaderConstants(Register, FirstCount, const_cast<VOID*>(pData)); if (FAILED(hr)) { D3D_THROW(hr, "Failed to set vertex shader constants"); } hr = GeometryFuncsGuaranteed->LoadShaderConstants(D3DVS_CONSTREG_MAX_V1_1, Register + count - D3DVS_CONSTREG_MAX_V1_1, &((DWORD*)pData)[FirstCount*4]); } } if (FAILED(hr)) { D3D_THROW(hr, "Failed to set vertex shader constants"); }
if (!(m_dwRuntimeFlags & D3DRT_EXECUTESTATEMODE)) { if (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) m_dwRuntimeFlags |= D3DRT_NEED_VSCONST_UPDATE; else m_pDDI->SetVertexShaderConstant(Register, pData, count); } DebugStateChanged( D3DDM_SC_VSCONSTANTS ); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::ValidateDraw2"
void CD3DHal::ValidateDraw2(D3DPRIMITIVETYPE primType, UINT StartVertex, UINT PrimitiveCount, UINT NumVertices, BOOL bIndexPrimitive, UINT StartIndex) { #if DBG
if (this->rstates[D3DRS_FILLMODE] == D3DFILL_POINT && m_dwRuntimeFlags & D3DRT_POINTSIZEPRESENT && primType != D3DPT_POINTLIST) { D3D_INFO(0, "Result of drawing primitives with D3DFILL_POINT fill mode " "and point size not equal 1.0f could be different on " "different devices"); } if ((m_dwHintFlags & D3DDEVBOOL_HINTFLAGS_INSCENE) == 0 && !(m_pv->dwFlags & D3DPV_VBCALL)) { D3D_THROW_FAIL("Need to call BeginScene before rendering."); } if (m_dwCurrentShaderHandle == 0) { D3D_THROW_FAIL("Invalid vertex shader handle (0x0)"); } if (bIndexPrimitive && primType == D3DPT_POINTLIST) { D3D_THROW_FAIL("Indexed point lists are not supported"); } if (*(FLOAT*)&rstates[D3DRS_PATCHSEGMENTS] > 1.f) { if (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) { D3D_THROW_FAIL("N-Patches are not supported with software vertex processing"); } else if ((GetD3DCaps()->DevCaps & (D3DDEVCAPS_NPATCHES | D3DDEVCAPS_RTPATCHES)) == 0) { D3D_THROW_FAIL("N-Patches are not supported"); } } BOOL bUserMemPrimitive = this->m_dwRuntimeFlags & D3DRT_USERMEMPRIMITIVE; if (D3DVSD_ISLEGACY(m_dwCurrentShaderHandle)) { // DX7 FVF handles can work only from stream zero
if (!bUserMemPrimitive) { if (m_pStream[0].m_pVB == NULL) { D3D_THROW_FAIL("Stream 0 should be initialized for FVF shaders"); } DWORD dwFVF = m_pStream[0].m_pVB->GetFVF(); if (dwFVF != 0 && dwFVF != m_dwCurrentShaderHandle) { D3D_THROW_FAIL("Current vertex shader doesn't match VB's FVF"); } if (FVF_TRANSFORMED(m_dwCurrentShaderHandle)) { if (!(m_pv->dwDeviceFlags & D3DDEV_DONOTCLIP) && m_pStream[0].m_pVB->GetBufferDesc()->Usage & D3DUSAGE_DONOTCLIP) { D3D_THROW_FAIL("Vertex buffer with D3DUSAGE_DONOTCLIP is used with clipping"); } } else { D3DVERTEXBUFFER_DESC Desc; static_cast<IDirect3DVertexBuffer8*>(m_pStream[0].m_pVB)->GetDesc(&Desc); if ((BehaviorFlags() & D3DCREATE_MIXED_VERTEXPROCESSING) != 0 && (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) != 0 && (Desc.Usage & D3DUSAGE_SOFTWAREPROCESSING) == 0 && Desc.Pool != D3DPOOL_SYSTEMMEM) { D3D_THROW_FAIL("Vertex buffer should have software usage or should be managed or should be in system memory"); } } if (m_pStream[0].m_pVB->IsLocked()) { D3D_THROW_FAIL("Vertex buffer must be unlocked during DrawPrimitive call"); } if (*((FLOAT*)&rstates[D3DRS_PATCHSEGMENTS]) > 1.f && (m_pStream[0].m_pVB->GetBufferDesc()->Usage & D3DUSAGE_NPATCHES) == 0) { D3D_THROW_FAIL("Vertex buffers used for rendering N-Patches should have D3DUSAGE_NPATCHES set"); } } // DX7 drivers cannot handle case when vertex size, computed from FVF,
// is different from the stream stride
if (m_pStream[0].m_dwStride != ComputeVertexSizeFVF(m_dwCurrentShaderHandle)) { D3D_THROW_FAIL("Stream 0 stride should match the stride, implied by the current vertex shader"); } if (m_pStream[0].m_dwNumVertices < (StartVertex + NumVertices)) { D3D_THROW_FAIL("Streams do not have required number of vertices"); } } else { if (m_pv->dwDeviceFlags & D3DDEV_VERTEXSHADERS) { CVShaderCode * pCode = m_pCurrentShader->m_pCode; for (DWORD i=0; i < D3DHAL_TSS_MAXSTAGES; i++) { if (this->tsstates[i][D3DTSS_TEXCOORDINDEX] != i) { D3D_ERR("Stage %d - Texture coordinate index in the stage " "must be equal to the stage index when programmable" " vertex pipeline is used", i); D3D_THROW_FAIL(""); } DWORD TexTransformFlags = tsstates[i][D3DTSS_TEXTURETRANSFORMFLAGS]; if (pCode) { if (TexTransformFlags & D3DTTFF_PROJECTED && !(m_dwRuntimeFlags & D3DRT_ONLY2FLOATSPERTEXTURE) && pCode->m_dwOutTexCoordSize[i] != 16) { D3D_ERR("Stage %d - Vertex shader must write XYZW to the " "output texture register when texture projection is enabled", i); D3D_THROW_FAIL(""); } } if ((TexTransformFlags & ~D3DTTFF_PROJECTED) != D3DTTFF_DISABLE) { D3D_ERR("Stage %d - Count in D3DTSS_TEXTURETRANSFORMFLAGS " "must be 0 when programmable pipeline is used", i); D3D_THROW_FAIL(""); } } }
if (m_pCurrentShader->m_Declaration.m_bStreamTessPresent) { D3D_THROW_FAIL("Declaration with tesselator stream cannot be used with DrawPrimitive API"); } if (((GetDDIType() < D3DDDITYPE_DX8)&& (m_pCurrentShader->m_Declaration.m_bLegacyFVF == FALSE)) && !(m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) ) { D3D_THROW_FAIL("Device does not support declarations"); } // Check if
// 1. streams, referenced by the current shader, are valid
// 2. stride in the current shader and in the stream matches
// 3. Compute max number of vertices the streams can contain
CVStreamDecl* pStream; pStream = m_pCurrentShader->m_Declaration.m_pActiveStreams; while(pStream) { UINT index = pStream->m_dwStreamIndex; CVStream* pDeviceStream = &m_pStream[index]; if (bUserMemPrimitive) { DXGASSERT(pDeviceStream->m_pData != NULL); if (index != 0) { D3D_THROW_FAIL("DrawPrimitiveUP can use declaration only with stream 0"); } } else { if (pDeviceStream->m_pVB == NULL) { D3D_ERR("Stream %d is not set, but used by current declaration", index); D3D_THROW_FAIL(""); } if (pDeviceStream->m_pVB->IsLocked()) { D3D_ERR("Vertex buffer in stream %d must be unlocked during drawing", index); D3D_THROW_FAIL(""); } D3DVERTEXBUFFER_DESC Desc; static_cast<IDirect3DVertexBuffer8*>(pDeviceStream->m_pVB)->GetDesc(&Desc); if ((BehaviorFlags() & D3DCREATE_MIXED_VERTEXPROCESSING) != 0 && (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) != 0 && (Desc.Usage & D3DUSAGE_SOFTWAREPROCESSING) == 0 && Desc.Pool != D3DPOOL_SYSTEMMEM) { D3D_INFO(0, "In stream %d vertex buffer should have software usage or should be managed or should be in system memory", pStream->m_dwStreamIndex); D3D_THROW_FAIL(""); } if (*((FLOAT*)&rstates[D3DRS_PATCHSEGMENTS]) > 1.f && (pDeviceStream->m_pVB->GetBufferDesc()->Usage & D3DUSAGE_NPATCHES) == 0) { D3D_THROW_FAIL("Vertex buffers used for rendering N-Patches should have D3DUSAGE_NPATCHES set"); } // Validate matching of FVF in the vertex buffer and stream
// declaration
if (m_pv->dwDeviceFlags & D3DDEV_VERTEXSHADERS) { if (pDeviceStream->m_pVB->GetFVF() != 0) { D3D_INFO(1, "In stream %d vertex buffer with FVF is " "used with programmable vertex shader", pStream->m_dwStreamIndex); } } else { // Fixed function pipeline case
DWORD vbFVF = pDeviceStream->m_pVB->GetFVF(); DWORD streamFVF = pStream->m_dwFVF; // VB FVF should be a superset of the stream FVF
if (vbFVF && ((vbFVF & streamFVF) != streamFVF)) { D3D_INFO(0, "In stream %d vertex buffer FVF and declaration FVF do not match", pStream->m_dwStreamIndex); } } } // Stride 0 is allowed
if (pDeviceStream->m_dwStride) { if (pDeviceStream->m_dwStride < pStream->m_dwStride) { D3D_ERR("Vertex strides in stream %d is less than in the declaration", index); D3D_THROW_FAIL(""); } if (pDeviceStream->m_dwNumVertices < (StartVertex + NumVertices)) { D3D_ERR("Stream %d does not have required number of vertices", pStream->m_dwStreamIndex); D3D_THROW_FAIL(""); } } pStream = (CVStreamDecl*)pStream->m_pNext; } } if (bIndexPrimitive) { if (!bUserMemPrimitive) { if (m_pIndexStream->m_pVBI == NULL) { D3D_THROW_FAIL("Index stream is not set"); } if (m_pIndexStream->m_pVBI->IsLocked()) { D3D_THROW_FAIL("Index buffer must be unlocked during drawing"); } UINT NumIndices = GETVERTEXCOUNT(primType, PrimitiveCount); if (m_pIndexStream->m_dwNumVertices < (StartIndex + NumIndices)) { D3D_THROW_FAIL("Index stream does not have required number of indices"); } if (FVF_TRANSFORMED(m_dwCurrentShaderHandle) && D3DVSD_ISLEGACY(m_dwCurrentShaderHandle)) { if (!(m_pv->dwDeviceFlags & D3DDEV_DONOTCLIP) && (m_pIndexStream->m_pVBI->GetBufferDesc()->Usage & D3DUSAGE_DONOTCLIP)) { D3D_THROW_FAIL("Index buffer with D3DUSAGE_DONOTCLIP is used with clipping"); } } else { D3DINDEXBUFFER_DESC Desc; static_cast<IDirect3DIndexBuffer8*>(m_pIndexStream->m_pVBI)->GetDesc(&Desc); if ((BehaviorFlags() & D3DCREATE_MIXED_VERTEXPROCESSING) != 0 && (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) != 0 && (Desc.Usage & D3DUSAGE_SOFTWAREPROCESSING) == 0 && Desc.Pool != D3DPOOL_SYSTEMMEM) { D3D_THROW_FAIL("Index buffer should have software usage or should be managed or should be in system memory"); } } if (*((FLOAT*)&rstates[D3DRS_PATCHSEGMENTS]) > 1.f && (m_pIndexStream->m_pVBI->GetBufferDesc()->Usage & D3DUSAGE_NPATCHES) == 0) { D3D_THROW_FAIL("Index buffers used for rendering N-Patches should have D3DUSAGE_NPATCHES set"); } } else { DXGASSERT(m_pIndexStream->m_pData != NULL); } } #endif //DBG
} //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::DrawPoints"
void CD3DHal::DrawPoints(UINT StartVertex) { BOOL bRecomputeOutputFVF = FALSE; // If point scale is enabled and device supports point sprites
// we may need to add the point size to the output FVF
if (rstates[D3DRS_POINTSCALEENABLE] && !(m_dwRuntimeFlags & D3DRT_POINTSIZEINVERTEX) && !(m_pv->dwDeviceFlags & D3DDEV_TRANSFORMEDFVF)) { ForceFVFRecompute(); bRecomputeOutputFVF = TRUE; } if (m_dwRuntimeFlags & D3DRT_DOPOINTSPRITEEMULATION) { // We do point sprite expansion when point size is not 1.0 in the
// render state or it is present in vertices or we need to do point
// scaling for untransformed vertices
if ((m_dwRuntimeFlags & D3DRT_POINTSIZEPRESENT || (rstates[D3DRS_POINTSCALEENABLE] && !(m_pv->dwDeviceFlags & D3DDEV_TRANSFORMEDFVF))) && // We do not do emulation for devices which supports point sprites,
// but only when there is no point size in the FVF
!(bRecomputeOutputFVF == FALSE && (m_dwRuntimeFlags & D3DRT_POINTSIZEINVERTEX) == 0 && m_dwRuntimeFlags & D3DRT_SUPPORTSPOINTSPRITES)) { m_pv->dwDeviceFlags |= D3DDEV_DOPOINTSPRITEEMULATION; m_pDDI->PickProcessPrimitive(); } else { if (m_pv->dwDeviceFlags & D3DDEV_TRANSFORMEDFVF && (m_pv->dwDeviceFlags & D3DDEV_DONOTCLIP || !(m_pv->dwDeviceFlags & D3DDEV_VBPROCVER))) { // Now we can call DDI directly, because no emulation is
// necessary
if (m_pStream[0].m_pVB) { (*m_pDDI->GetDrawPrimFunction())(this, m_pv->primType, StartVertex, m_pv->dwNumPrimitives); } else { m_pDDI->SetVertexShader(m_dwCurrentShaderHandle); m_pDDI->SetStreamSource(0, &m_pStream[0]); m_pDDI->DrawPrimitiveUP(m_pv->primType, m_pv->dwNumPrimitives); } return; } } }
(this->*m_pfnPrepareToDraw)(StartVertex); (m_pDDI->*m_pDDI->m_pfnProcessPrimitive)(m_pv, StartVertex);
if (bRecomputeOutputFVF) { ForceFVFRecompute(); } m_pv->dwDeviceFlags &= ~D3DDEV_DOPOINTSPRITEEMULATION; m_pDDI->PickProcessPrimitive(); } //-----------------------------------------------------------------------------
// Draw all primitive types except points
//
#undef DPF_MODNAME
#define DPF_MODNAME "DrawPrimitiveHal"
void CD3DHal_DrawPrimitive(CD3DBase* pBaseDevice, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) { CD3DHal* pDevice = static_cast<CD3DHal*>(pBaseDevice); CD3DDDIDX6* pDDI = pBaseDevice->m_pDDI;
#if DBG
UINT nVer = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount); pDevice->ValidateDraw2(PrimitiveType, StartVertex, PrimitiveCount, nVer, FALSE); #endif
D3DFE_PROCESSVERTICES* pv = pDevice->m_pv; pv->primType = PrimitiveType; pv->dwNumPrimitives = PrimitiveCount; pv->dwNumVertices = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount); pv->dwFlags &= D3DPV_PERSIST; (pDevice->*pDevice->m_pfnPrepareToDraw)(StartVertex); (pDDI->*pDDI->m_pfnProcessPrimitive)(pv, StartVertex); } //-----------------------------------------------------------------------------
// Draw only points
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::DrawPointsI"
void CD3DHal::DrawPointsI(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) { #if DBG
UINT nVer = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount); ValidateDraw2(PrimitiveType, StartVertex, PrimitiveCount, nVer, FALSE); #endif
if (!(m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) || CanCallDriver(this, PrimitiveType)) { (*m_pfnDrawPrim)(this, PrimitiveType, StartVertex, PrimitiveCount); } else { m_pv->primType = PrimitiveType; m_pv->dwNumPrimitives = PrimitiveCount; m_pv->dwNumVertices = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount); m_pv->dwFlags &= D3DPV_PERSIST; DrawPoints(StartVertex); } } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal_DrawIndexedPrimitive"
void CD3DHal_DrawIndexedPrimitive(CD3DBase* pBaseDevice, D3DPRIMITIVETYPE PrimitiveType, UINT BaseIndex, UINT MinIndex, UINT NumVertices, UINT StartIndex, UINT PrimitiveCount) { CD3DHal* pDevice = static_cast<CD3DHal*>(pBaseDevice); CVIndexStream* pIndexStream = pBaseDevice->m_pIndexStream; CD3DDDIDX6* pDDI = pBaseDevice->m_pDDI;
#if DBG
pDevice->ValidateDraw2(PrimitiveType, MinIndex + pIndexStream->m_dwBaseIndex, PrimitiveCount, NumVertices, TRUE, StartIndex); #endif
D3DFE_PROCESSVERTICES* pv = pDevice->m_pv; pIndexStream->m_pData = NULL; pv->primType = PrimitiveType; pv->dwNumPrimitives = PrimitiveCount; pv->dwFlags &= D3DPV_PERSIST;
pv->dwNumVertices = NumVertices; pv->dwNumIndices = GETVERTEXCOUNT(PrimitiveType, PrimitiveCount); pv->dwIndexSize = pIndexStream->m_dwStride; UINT StartVertex = MinIndex + pIndexStream->m_dwBaseIndex; pDDI->SetIndexedPrimParams(StartIndex, MinIndex, NumVertices, pIndexStream->m_dwBaseIndex); (pDevice->*pDevice->m_pfnPrepareToDraw)(StartVertex); (pDDI->*pDDI->m_pfnProcessIndexedPrimitive)(pv, StartVertex); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::DrawPrimitiveUPI"
void CD3DHal::DrawPrimitiveUPI(D3DPRIMITIVETYPE PrimType, UINT PrimCount)
{ #if DBG
UINT nVer = GETVERTEXCOUNT(PrimType, PrimCount); ValidateDraw2(PrimType, 0, PrimCount, nVer, FALSE); #endif
m_pv->dwDeviceFlags &= ~D3DDEV_VBPROCVER; if (!(m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING)) { if (m_dwRuntimeFlags & D3DRT_DONPATCHCONVERSION && PrimType >= D3DPT_TRIANGLELIST) { CD3DHal_DrawNPatch(this, PrimType, 0, PrimCount); } else { m_pDDI->DrawPrimitiveUP(PrimType, PrimCount); } } else if (CanCallDriver(this, PrimType)) { m_pDDI->SetVertexShader(m_dwCurrentShaderHandle); m_pDDI->SetStreamSource(0, &m_pStream[0]); m_pDDI->DrawPrimitiveUP(PrimType, PrimCount); } else { SetupStrides(m_pv, m_pStream[0].m_dwStride); m_pv->primType = PrimType; m_pv->dwNumPrimitives = PrimCount; m_pv->dwNumVertices = GETVERTEXCOUNT(PrimType, PrimCount); m_pv->dwFlags &= D3DPV_PERSIST; if (PrimType != D3DPT_POINTLIST) { (this->*m_pfnPrepareToDraw)(0); (m_pDDI->*m_pDDI->m_pfnProcessPrimitive)(m_pv, 0); } else DrawPoints(0); } } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::DrawIndexedPrimitiveUPI"
void CD3DHal::DrawIndexedPrimitiveUPI(D3DPRIMITIVETYPE PrimType, UINT MinVertexIndex, UINT NumVertices, UINT PrimCount) { #if DBG
ValidateDraw2(PrimType, 0, PrimCount, NumVertices, TRUE); #endif
m_pv->dwDeviceFlags &= ~D3DDEV_VBPROCVER; if (!(m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING)) { if (m_dwRuntimeFlags & D3DRT_DONPATCHCONVERSION && PrimType >= D3DPT_TRIANGLELIST) { CD3DHal_DrawIndexedNPatch(this, PrimType, 0, MinVertexIndex, NumVertices, 0, PrimCount); } else { m_pDDI->DrawIndexedPrimitiveUP(PrimType, MinVertexIndex, NumVertices, PrimCount); } } else if (CanCallDriver(this, PrimType)) { m_pDDI->SetVertexShader(m_dwCurrentShaderHandle); m_pDDI->SetStreamSource(0, &m_pStream[0]); m_pDDI->SetIndices(m_pIndexStream); m_pDDI->DrawIndexedPrimitiveUP(PrimType, MinVertexIndex, NumVertices, PrimCount); } else { SetupStrides(m_pv, m_pStream[0].m_dwStride); m_pv->primType = PrimType; m_pv->dwNumPrimitives = PrimCount; m_pv->dwFlags &= D3DPV_PERSIST;
m_pv->dwNumVertices = NumVertices; m_pv->dwNumIndices = GETVERTEXCOUNT(PrimType, PrimCount); m_pv->lpwIndices = (WORD*)m_pIndexStream->m_pData; m_pv->dwIndexSize = m_pIndexStream->m_dwStride; m_pDDI->SetIndexedPrimParams(0, MinVertexIndex, MinVertexIndex + NumVertices, 0); (this->*m_pfnPrepareToDraw)(MinVertexIndex); (m_pDDI->*m_pDDI->m_pfnProcessIndexedPrimitive)(m_pv, MinVertexIndex); } } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "SetupFVFDataVVM"
void SetupFVFDataVVM(CD3DHal* pDev) { D3DFE_PROCESSVERTICES* pv = pDev->m_pv; // We have to restore texture stage indices if previous primitive
// re-mapped them
if (pv->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { RestoreTextureStages(pDev); }
// Input FVF has no meaning for vertex shaders, but it is used for validaion
pv->dwVIDIn = 0;
// Compute output FVF
CVShaderCode * pCode = pDev->m_pCurrentShader->m_pCode;
pv->dwVIDOut = pCode->m_dwOutFVF; pv->dwOutputSize = pCode->m_dwOutVerSize; pv->nOutTexCoord = pCode->m_nOutTexCoord; // We use offsets, computed by the vertex shader
pv->pointSizeOffsetOut = pCode->m_dwPointSizeOffset; pv->diffuseOffsetOut = pCode->m_dwDiffuseOffset; pv->specularOffsetOut = pCode->m_dwSpecularOffset; pv->fogOffsetOut = pCode->m_dwFogOffset; pv->texOffsetOut = pCode->m_dwTextureOffset; pv->dwTextureCoordSizeTotal = 0; for (DWORD i=0; i < pv->nOutTexCoord; i++) { DWORD dwSize = pCode->m_dwOutTexCoordSize[i]; pv->dwTextureCoordSize[i] = dwSize; pv->dwTextureCoordSizeTotal += dwSize; } } //----------------------------------------------------------------------
void CD3DHal::SetupFVFData() { CD3DHal::SetupFVFDataCommon(); if (!(m_pv->dwVIDIn & D3DFVF_NORMAL)) m_pv->dwDeviceFlags &= ~D3DDEV_NORMALINCAMERASPACE; } //---------------------------------------------------------------------
// Computes the following data
// - dwTextureCoordOffset[] offset of every input texture coordinates
static __inline void ComputeInpTexCoordOffsets(DWORD dwNumTexCoord, DWORD dwFVF, DWORD *pdwTextureCoordOffset) { // Compute texture coordinate size
DWORD dwTextureFormats = dwFVF >> 16; if (dwTextureFormats == 0) { for (DWORD i=0; i < dwNumTexCoord; i++) { pdwTextureCoordOffset[i] = i << 3; } } else { DWORD dwOffset = 0; for (DWORD i=0; i < dwNumTexCoord; i++) { pdwTextureCoordOffset[i] = dwOffset; dwOffset += g_TextureSize[dwTextureFormats & 3]; dwTextureFormats >>= 2; } } return; } //---------------------------------------------------------------------
// Returns 2 bits of FVF texture format for the texture index
//
static inline DWORD FVFGetTextureFormat(DWORD dwFVF, DWORD dwTextureIndex) { return (dwFVF >> (dwTextureIndex*2 + 16)) & 3; } //---------------------------------------------------------------------
// Returns texture format bits shifted to the right place
//
static inline DWORD FVFMakeTextureFormat(DWORD dwNumberOfCoordinates, DWORD dwTextureIndex) { return g_dwTextureFormat[dwNumberOfCoordinates] << ((dwTextureIndex << 1) + 16); } //---------------------------------------------------------------------
inline DWORD GetOutTexCoordSize(DWORD *pdwStage, DWORD dwInpTexCoordSize) { // Low byte has texture coordinate count
const DWORD dwTextureTransformFlags = pdwStage[D3DTSS_TEXTURETRANSFORMFLAGS] & 0xFF; if (dwTextureTransformFlags == 0) return dwInpTexCoordSize; else return (dwTextureTransformFlags << 2); } //----------------------------------------------------------------------
// pDevI->nOutTexCoord should be initialized to the number of input texture coord sets
//
void EvalTextureTransforms(LPD3DHAL pDevI, DWORD dwTexTransform, DWORD *pdwOutTextureSize, DWORD *pdwOutTextureFormat) { D3DFE_PROCESSVERTICES* pv = pDevI->m_pv; DWORD dwOutTextureSize = 0; // Used to compute output vertex size
DWORD dwOutTextureFormat = 0; // Used to compute output texture FVF
// The bits are used to find out how the texture coordinates are used.
const DWORD __USED_BY_TRANSFORM = 1; const DWORD __USED = 2; const DWORD __USED_TEXTURE_PROJECTION = 4; // The low 16 bits are for _USED bits. The high 16 bits will hold
// re-mapped texture index for a stage
DWORD dwTexCoordUsage[D3DDP_MAXTEXCOORD]; memset(dwTexCoordUsage, 0, sizeof(dwTexCoordUsage));
// Re-mapping buffer will contain only stages that use texture
// This variable is used to count them
pDevI->dwNumTextureStagesToRemap = 0; DWORD dwNewIndex = 0; // Used to generate output index
// We need offsets for every input texture coordinate, because
// we could access them in random order.
// Offsets are not needed for strided input
DWORD dwTextureCoordOffset[D3DDP_MAXTEXCOORD]; if (!(pv->dwDeviceFlags & D3DDEV_STRIDE)) { ComputeInpTexCoordOffsets(pv->nTexCoord, pv->dwVIDIn, dwTextureCoordOffset); } DWORD dwOutTextureCoordSize[D3DDP_MAXTEXCOORD]; // TRUE, if we do not do texture projection and transform for a stage,
// because the stage does not have corresponding texture coordinates in the
// input
BOOL bIgnoreTexCoord = FALSE; // Go through all texture stages and find those wich use texture coordinates
for (DWORD i=0; i < D3DDP_MAXTEXCOORD; i++) { if (pDevI->tsstates[i][D3DTSS_COLOROP] == D3DTOP_DISABLE) break;
DWORD dwIndex = pDevI->tsstates[i][D3DTSS_TEXCOORDINDEX]; DWORD dwInpTextureFormat; DWORD dwInpTexSize; LPD3DFE_TEXTURESTAGE pStage = &pDevI->textureStageToRemap[pDevI->dwNumTextureStagesToRemap]; DWORD dwTexGenMode = dwIndex & ~0xFFFF; pStage->dwInpOffset = 0; dwIndex = dwIndex & 0xFFFF; // Remove texture generation mode
if (dwTexGenMode == D3DTSS_TCI_CAMERASPACENORMAL || dwTexGenMode == D3DTSS_TCI_CAMERASPACEPOSITION || dwTexGenMode == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR) { dwInpTextureFormat = D3DFVF_TEXCOORDSIZE3(dwIndex); dwInpTexSize = 3*sizeof(D3DVALUE); pv->dwDeviceFlags |= D3DDEV_REMAPTEXTUREINDICES; if (dwTexGenMode == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR) pv->dwDeviceFlags |= D3DDEV_NORMALINCAMERASPACE | D3DDEV_POSITIONINCAMERASPACE; else if (dwTexGenMode == D3DTSS_TCI_CAMERASPACENORMAL) pv->dwDeviceFlags |= D3DDEV_NORMALINCAMERASPACE; else if (dwTexGenMode == D3DTSS_TCI_CAMERASPACEPOSITION) pv->dwDeviceFlags |= D3DDEV_POSITIONINCAMERASPACE; } else { if (dwIndex >= pv->nTexCoord) { // This could happen when input vertex does not have texture
// coordinates, but it is OK, because texture pointer in the
// stage could be NULL, or the stage does not use texture, or
// pixel shader is used.
// It is too complex and error prone to check all cases when
// this is an user error, so we just make this case to work.
dwIndex = 0; dwInpTexSize = sizeof(float)*2; dwInpTextureFormat = 0; // Ignore special texture coordinate processing for this stage
bIgnoreTexCoord = TRUE; // Disable texture transform for the stage
dwTexTransform &= ~1; pStage->dwInpOffset = 0; } else { dwInpTexSize = pv->dwTextureCoordSize[dwIndex]; dwInpTextureFormat = FVFGetTextureFormat(pv->dwVIDIn, dwIndex); pStage->dwInpOffset = dwTextureCoordOffset[dwIndex]; } } pStage->dwInpCoordIndex = dwIndex; pStage->dwTexGenMode = dwTexGenMode; pStage->dwOrgStage = i; pStage->bDoTextureProjection = FALSE; DWORD dwOutTexCoordSize; // Size of the texture coord set in bytes for this stage
if (dwTexTransform & 1) { pv->dwDeviceFlags |= D3DDEV_TEXTURETRANSFORM; pStage->pmTextureTransform = &pv->mTexture[i]; dwOutTexCoordSize = GetOutTexCoordSize((DWORD*)&pDevI->tsstates[i], dwInpTexSize); // If we have to add or remove some coordinates we go through
// the re-mapping path
if (dwOutTexCoordSize != dwInpTexSize) pv->dwDeviceFlags |= D3DDEV_REMAPTEXTUREINDICES; pStage->dwTexTransformFuncIndex = MakeTexTransformFuncIndex (dwInpTexSize >> 2, dwOutTexCoordSize >> 2); } else { pStage->pmTextureTransform = NULL; dwOutTexCoordSize = dwInpTexSize; pStage->dwTexTransformFuncIndex = 0; } if (NeedTextureProjection(pv, i) && !bIgnoreTexCoord) { // Remove one float from the output
dwOutTexCoordSize -= 4; // Set re-mapping so we do not complicate simple case
pv->dwDeviceFlags |= D3DDEV_REMAPTEXTUREINDICES; // Texture projection is required for the stage
pStage->bDoTextureProjection = TRUE; } if ((dwTexCoordUsage[dwIndex] & 0xFFFF) == 0) { // Texture coordinate set is used first time
if (dwTexTransform & 1) dwTexCoordUsage[dwIndex] |= __USED_BY_TRANSFORM; dwTexCoordUsage[dwIndex] |= __USED; if (pStage->bDoTextureProjection) dwTexCoordUsage[dwIndex] |= __USED_TEXTURE_PROJECTION; } else { // Texture coordinate set is used second or more time
if (dwTexTransform & 1) { // This set is used by two texture transforms or a
// texture transform and without it, so we have to
// generate an additional output texture coordinate
dwTexCoordUsage[dwIndex] |= __USED_BY_TRANSFORM; pv->dwDeviceFlags |= D3DDEV_REMAPTEXTUREINDICES; } else { if (dwTexCoordUsage[dwIndex] & __USED_BY_TRANSFORM) { // This set is used by two texture transforms or a
// texture transform and without it, so we have to
// generate an additional output texture coordinate
pv->dwDeviceFlags |= D3DDEV_REMAPTEXTUREINDICES; } else // We can re-use the same input texture coordinate if there is no
// texture generation and texture projection flag is the same for both
// stages
if (dwTexGenMode == 0 && (pStage->bDoTextureProjection == ((dwTexCoordUsage[dwIndex] & __USED_TEXTURE_PROJECTION) != 0))) { DWORD dwOutIndex = dwTexCoordUsage[dwIndex] >> 16; pStage->dwOutCoordIndex = dwOutIndex; // Mark the stage as not to be used in the vertex processing loop
pStage->dwInpOffset = 0xFFFFFFFF; goto l_NoNewOutTexCoord; } } } // If we are here, we have to generate new output texture coordinate set
pStage->dwOutCoordIndex = dwNewIndex; dwTexCoordUsage[dwIndex] |= dwNewIndex << 16; dwOutTextureSize += dwOutTexCoordSize; dwOutTextureCoordSize[dwNewIndex] = dwOutTexCoordSize; dwOutTextureFormat |= FVFMakeTextureFormat(dwOutTexCoordSize >> 2, dwNewIndex); dwNewIndex++; l_NoNewOutTexCoord: pDevI->dwNumTextureStagesToRemap++; dwTexTransform >>= 1; } if (pv->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { // Now, when we have to do re-mapping, we have to set new output texture
// coordinate set sizes and we need to remove stages, which do not produce
// output texture coordinates.
DWORD dwNumTextureStages = 0; for (DWORD i=0; i < pDevI->dwNumTextureStagesToRemap; i++) { if (pDevI->textureStageToRemap[i].dwInpOffset != 0xFFFFFFFF) { pv->textureStage[dwNumTextureStages] = pDevI->textureStageToRemap[i]; pv->dwTextureCoordSize[dwNumTextureStages] = dwOutTextureCoordSize[dwNumTextureStages]; dwNumTextureStages++; } pv->dwNumTextureStages = dwNumTextureStages; } pv->nOutTexCoord = dwNewIndex; } *pdwOutTextureSize = dwOutTextureSize; *pdwOutTextureFormat = dwOutTextureFormat; } //----------------------------------------------------------------------
// Sets texture transform pointer for every input texture coordinate set
//
void SetupTextureTransforms(LPD3DHAL pDevI) { D3DFE_PROCESSVERTICES* pv = pDevI->m_pv; // Set texture transforms to NULL in case when some texture coordinates
// are not used by texture stages
memset(pv->pmTexture, 0, sizeof(pv->pmTexture));
for (DWORD i=0; i < pDevI->dwNumTextureStagesToRemap; i++) { LPD3DFE_TEXTURESTAGE pStage = &pDevI->textureStageToRemap[i]; pv->pmTexture[pStage->dwInpCoordIndex] = pStage->pmTextureTransform; } } //----------------------------------------------------------------------
// Computes the following device data
// - dwVIDOut, based on input FVF id and device settings
// - nTexCoord
// - dwTextureCoordSizeTotal
// - dwTextureCoordSize[] array, based on the input FVF id
// - dwOutputSize, based on the output FVF id
//
// The function is called from ProcessVertices and DrawPrimitives code paths
//
// The following variables should be set in the pDevI:
// - dwVIDIn
//
// Number of texture coordinates is set based on dwVIDIn. ValidateFVF should
// make sure that it is not greater than supported by the driver
// Last settings for dwVIDOut and dwVIDIn are saved to speed up processing
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::SetupFVFDataCommon"
void CD3DHal::SetupFVFDataCommon() { HRESULT ret; this->dwFEFlags &= ~D3DFE_FVF_DIRTY; // We have to restore texture stage indices if previous primitive
// re-mapped them
if (m_pv->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { RestoreTextureStages(this); }
// Compute number of the input texture coordinates
m_pv->nTexCoord = FVF_TEXCOORD_NUMBER(m_pv->dwVIDIn);
// Compute size of input texture coordinates
m_pv->dwTextureCoordSizeTotal = ComputeTextureCoordSize(m_pv->dwVIDIn, m_pv->dwInpTextureCoordSize);
// This size is the same for input and output FVFs in case when we do not have to
// expand number of texture coordinates
for (DWORD i=0; i < m_pv->nTexCoord; i++) m_pv->dwTextureCoordSize[i] = m_pv->dwInpTextureCoordSize[i];
m_pv->nOutTexCoord = m_pv->nTexCoord;
// Setup input vertex offsets
UpdateGeometryLoopData(m_pv);
if (FVF_TRANSFORMED(m_pv->dwVIDIn)) { // Set up vertex pointers
m_pv->dwVIDOut = m_pv->dwVIDIn; ComputeOutputVertexOffsets(m_pv); m_pv->dwOutputSize = ComputeVertexSizeFVF(m_pv->dwVIDOut); return; }
// Compute output FVF
m_pv->dwVIDOut = D3DFVF_XYZRHW; if (m_pv->dwDeviceFlags & D3DDEV_DONOTSTRIPELEMENTS && !(m_pv->dwFlags & D3DPV_VBCALL)) { m_pv->dwVIDOut |= D3DFVF_DIFFUSE | D3DFVF_SPECULAR; } else { // If normal present we have to compute specular and duffuse
// Otherwise set these bits the same as input.
// Not that normal should not be present for XYZRHW position type
if (m_pv->dwDeviceFlags & D3DDEV_LIGHTING) m_pv->dwVIDOut |= D3DFVF_DIFFUSE | D3DFVF_SPECULAR; else m_pv->dwVIDOut |= m_pv->dwVIDIn & (D3DFVF_DIFFUSE | D3DFVF_SPECULAR); // Always set specular flag if vertex fog is enabled
if (this->rstates[D3DRENDERSTATE_FOGENABLE] && m_pv->lighting.fog_mode != D3DFOG_NONE) { m_pv->dwVIDOut |= D3DFVF_SPECULAR; } else // Clear specular flag if specular disabled and we do not have
// specular in the input
if (!this->rstates[D3DRENDERSTATE_SPECULARENABLE] && !(m_pv->dwVIDIn & D3DFVF_SPECULAR)) { m_pv->dwVIDOut &= ~D3DFVF_SPECULAR; } } if (m_pv->dwVIDIn & D3DFVF_PSIZE || m_pv->primType == D3DPT_POINTLIST && this->rstates[D3DRS_POINTSCALEENABLE]) { m_pv->dwVIDOut |= D3DFVF_PSIZE; }
// Compute number of the output texture coordinates
// Transform enable bits
m_pv->dwDeviceFlags &= ~D3DDEV_TEXTURETRANSFORM;
DWORD dwTexTransform = m_pv->dwFlags2 & __FLAGS2_TEXTRANSFORM;
// When texture transform is enabled or we need to do projected texture
// emulation or texture coordinates are taken from the vertex data (texgen),
// output texture coordinates could be generated.
// So we go and evaluate texture stages
if ((m_pv->dwFlags2 & (__FLAGS2_TEXTRANSFORM | __FLAGS2_TEXPROJ) && (m_pv->nTexCoord > 0)) || m_pv->dwFlags2 & __FLAGS2_TEXGEN) { DWORD dwOutTextureSize; // Used to compute output vertex size
DWORD dwOutTextureFormat; // Used to compute output texture FVF
// There are texture transforms.
// Now we find out if some of the texture coordinates are used two
// or more times and used by a texture transform. In this case we
// have expand number of output texture coordinates.
EvalTextureTransforms(this, dwTexTransform, &dwOutTextureSize, &dwOutTextureFormat); if (m_pv->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { // For ProcessVertices calls user should set texture stages and
// wrap modes himself
if (!(m_pv->dwFlags & D3DPV_VBCALL)) { // dwVIDIn is used to force re-compute FVF in the
// SetTextureStageState. so we save and restore it.
DWORD dwVIDInSaved = m_pv->dwVIDIn; // Re-map indices in the texture stages and wrap modes
DWORD dwOrgWrapModes[D3DDP_MAXTEXCOORD]; memcpy(dwOrgWrapModes, &this->rstates[D3DRENDERSTATE_WRAP0], sizeof(dwOrgWrapModes)); for (DWORD i=0; i < this->dwNumTextureStagesToRemap; i++) { LPD3DFE_TEXTURESTAGE pStage = &this->textureStageToRemap[i]; DWORD dwOutIndex = pStage->dwOutCoordIndex; DWORD dwInpIndex = pStage->dwInpCoordIndex; if (dwOutIndex != dwInpIndex || pStage->dwTexGenMode) { DWORD dwState = D3DRENDERSTATE_WRAP0 + dwOutIndex; pStage->dwOrgWrapMode = dwOrgWrapModes[dwOutIndex]; DWORD dwValue = dwOrgWrapModes[dwInpIndex]; // We do not call UpdateInternaState because it
// will call ForceRecomputeFVF and we do not want this.
this->rstates[dwState] = dwValue;
m_pDDI->SetRenderState((D3DRENDERSTATETYPE)dwState, dwValue);
// We do not call UpdateInternalTextureStageState because it
// will call ForceRecomputeFVF and we do not want this.
m_pDDI->SetTSS(pStage->dwOrgStage, D3DTSS_TEXCOORDINDEX, dwOutIndex); // We do not call UpdateInternalTextureStageState because it
// will call ForceRecomputeFVF and we do not want this.
// We set some invalid value to the internal array, because otherwise
// a new SetTextureStageState could be filtered as redundant
tsstates[pStage->dwOrgStage][D3DTSS_TEXCOORDINDEX] = 0xFFFFFFFF; } } m_pv->dwVIDIn = dwVIDInSaved; } else { } m_pv->dwVIDOut |= dwOutTextureFormat; m_pv->dwTextureCoordSizeTotal = dwOutTextureSize; } else { // We do not do re-mapping but we have to make correspondence between
// texture sets and texture transforms
SetupTextureTransforms(this);
// Copy input texture formats
m_pv->dwVIDOut |= m_pv->dwVIDIn & 0xFFFF0000; } } else { // Copy input texture formats
m_pv->dwVIDOut |= m_pv->dwVIDIn & 0xFFFF0000; // When we have texture coordinate set with number of floats different
// from 2 and device does not support them, we "fix" the texture format
if (m_pv->dwVIDOut & 0xFFFF0000) { if (m_dwRuntimeFlags & D3DRT_ONLY2FLOATSPERTEXTURE) { m_pv->dwVIDOut &= ~0xFFFF0000; for (DWORD i=0; i < m_pv->nOutTexCoord; i++) m_pv->dwTextureCoordSize[i] = 8; m_pv->dwTextureCoordSizeTotal = m_pv->nTexCoord * 8; } } }
if (m_pv->dwDeviceFlags & D3DDEV_DONOTSTRIPELEMENTS) { if (m_pv->nOutTexCoord == 0 && !(m_pv->dwFlags & D3DPV_VBCALL)) { m_pv->dwTextureCoordSize[0] = 0; m_pv->dwVIDOut |= (1 << D3DFVF_TEXCOUNT_SHIFT); } } // Set up number of output texture coordinates
m_pv->dwVIDOut |= (m_pv->nOutTexCoord << D3DFVF_TEXCOUNT_SHIFT); if ((m_pv->dwVIDOut & 0xFFFF0000) && (GetDDIType() < D3DDDITYPE_DX7)) { D3D_THROW_FAIL("Texture format bits in the output FVF for this device should be 0"); }
if (!(m_pv->dwFlags & D3DPV_VBCALL)) { m_pv->dwOutputSize = ComputeVertexSizeFVF(m_pv->dwVIDOut); ComputeOutputVertexOffsets(m_pv); }
// In case if COLORVERTEX is TRUE, the vertexAlpha could be overriden
// by vertex alpha
m_pv->lighting.alpha = (DWORD)m_pv->lighting.materialAlpha; m_pv->lighting.alphaSpecular = (DWORD)m_pv->lighting.materialAlphaS;
this->dwFEFlags |= D3DFE_VERTEXBLEND_DIRTY | D3DFE_FRONTEND_DIRTY; } //-----------------------------------------------------------------------------
// Sets input vertex pointers and output offsets for legacy vertex shaders for
// the programmable vertex shaders
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::PrepareToDrawVVM"
void CD3DHal::PrepareToDrawVVM(UINT StartVertex) { if (m_dwRuntimeFlags & D3DRT_SHADERDIRTY) { SetupFVFDataVVM(this); m_dwRuntimeFlags &= ~D3DRT_SHADERDIRTY; m_pDDI->SetVertexShader(m_pv->dwVIDOut); } // Initialize vertex pointers used in the vertex loop
CVertexDesc* pVD = m_pv->VertexDesc; for (DWORD i = m_pv->dwNumUsedVertexDescs; i; i--) { CVStream* pStream = pVD->pStream; DWORD dwStride = pStream->m_dwStride; pVD->pMemory = pStream->Data() + pVD->dwVertexOffset + StartVertex * dwStride; pVD->dwStride = dwStride; pVD++; } } //-----------------------------------------------------------------------------
// Sets input vertex pointers and output offsets for legacy vertex shaders
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::PrepareToDrawLegacy"
void CD3DHal::PrepareToDrawLegacy(UINT StartVertex) { // For legacy FVFs we draw using Stream[0]
m_pv->position.lpvData = m_pStream[0].Data() + m_pStream[0].m_dwStride * StartVertex; if (m_dwRuntimeFlags & D3DRT_SHADERDIRTY) { SetupFVFData(); m_pDDI->SetVertexShader(m_pv->dwVIDOut); m_dwRuntimeFlags &= ~D3DRT_SHADERDIRTY; } } //-----------------------------------------------------------------------------
// Sets input vertex pointers and output offsets for the fixed-function pipeline
// and non-legacy vertex declarations
//
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::PrepareToDraw"
void CD3DHal::PrepareToDraw(UINT StartVertex) { // Initialize strided data pointers used in the vertex loop
#if DBG
{ // Set all NULL pointers to check if they are initialized by the
// declaration
for (DWORD i=0; i < __NUMELEMENTS; i++) { m_pv->elements[i].lpvData = NULL; } } #endif
CVertexDesc* pVD = m_pv->VertexDesc; for (DWORD i = m_pv->dwNumUsedVertexDescs; i; i--) { CVStream* pStream = pVD->pStream; DWORD dwStride = pStream->m_dwStride; pVD->pElement->lpvData = pStream->Data() + pVD->dwVertexOffset + StartVertex * dwStride; pVD->pElement->dwStride = dwStride; pVD++; } if (m_dwRuntimeFlags & D3DRT_SHADERDIRTY) { SetupFVFData(); m_pDDI->SetVertexShader(m_pv->dwVIDOut); m_dwRuntimeFlags &= ~D3DRT_SHADERDIRTY; } } //-----------------------------------------------------------------------------
//
// Object implementations
//
//---------------------------------------------------------------------
const DWORD CVShader::FIXEDFUNCTION = 1; const DWORD CVShader::SOFTWARE = 2;
void CheckForNull(LPVOID p, DWORD line, char* file) { if (p == NULL) D3D_THROW_LINE(E_OUTOFMEMORY, "Not enough memory", line, file); }
//-----------------------------------------------------------------------------
void Copy_FLOAT1(LPVOID pInputStream, UINT stride, UINT count, VVM_WORD * pVertexRegister) { for (UINT i=0; i < count; i++) { pVertexRegister->x = *(float*)pInputStream; pVertexRegister->y = 0; pVertexRegister->z = 0; pVertexRegister->w = 1; pInputStream = (BYTE*)pInputStream + stride; pVertexRegister++; } }
void Copy_FLOAT2(LPVOID pInputStream, UINT stride, UINT count, VVM_WORD * pVertexRegister) { for (UINT i=0; i < count; i++) { pVertexRegister->x = ((float*)pInputStream)[0]; pVertexRegister->y = ((float*)pInputStream)[1]; pVertexRegister->z = 0; pVertexRegister->w = 1; pInputStream = (BYTE*)pInputStream + stride; pVertexRegister++; } }
void Copy_FLOAT3(LPVOID pInputStream, UINT stride, UINT count, VVM_WORD * pVertexRegister) { for (UINT i=0; i < count; i++) { pVertexRegister->x = ((float*)pInputStream)[0]; pVertexRegister->y = ((float*)pInputStream)[1]; pVertexRegister->z = ((float*)pInputStream)[2]; pVertexRegister->w = 1; pInputStream = (BYTE*)pInputStream + stride; pVertexRegister++; } }
void Copy_FLOAT4(LPVOID pInputStream, UINT stride, UINT count, VVM_WORD * pVertexRegister) { for (UINT i=0; i < count; i++) { pVertexRegister->x = ((float*)pInputStream)[0]; pVertexRegister->y = ((float*)pInputStream)[1]; pVertexRegister->z = ((float*)pInputStream)[2]; pVertexRegister->w = ((float*)pInputStream)[3]; pInputStream = (BYTE*)pInputStream + stride; pVertexRegister++; } }
void Copy_D3DCOLOR(LPVOID pInputStream, UINT stride, UINT count, VVM_WORD * pVertexRegister) { const float scale = 1.0f/255.f; for (UINT i=0; i < count; i++) { const DWORD v = ((DWORD*)pInputStream)[0]; pVertexRegister->x = scale * RGBA_GETRED(v); pVertexRegister->y = scale * RGBA_GETGREEN(v); pVertexRegister->z = scale * RGBA_GETBLUE(v); pVertexRegister->w = scale * RGBA_GETALPHA(v); pInputStream = (BYTE*)pInputStream + stride; pVertexRegister++; } }
void Copy_UBYTE4(LPVOID pInputStream, UINT stride, UINT count, VVM_WORD * pVertexRegister) { for (UINT i=0; i < count; i++) { const BYTE* v = (BYTE*)pInputStream; pVertexRegister->x = v[0]; pVertexRegister->y = v[1]; pVertexRegister->z = v[2]; pVertexRegister->w = v[3]; pInputStream = (BYTE*)pInputStream + stride; pVertexRegister++; } }
void Copy_SHORT2(LPVOID pInputStream, UINT stride, UINT count, VVM_WORD * pVertexRegister) { for (UINT i=0; i < count; i++) { const short* v = (short*)pInputStream; pVertexRegister->x = v[0]; pVertexRegister->y = v[1]; pVertexRegister->z = 0; pVertexRegister->w = 1; pInputStream = (BYTE*)pInputStream + stride; pVertexRegister++; } }
void Copy_SHORT4(LPVOID pInputStream, UINT stride, UINT count, VVM_WORD * pVertexRegister) { for (UINT i=0; i < count; i++) { const short* v = (short*)pInputStream; pVertexRegister->x = v[0]; pVertexRegister->y = v[1]; pVertexRegister->z = v[2]; pVertexRegister->w = v[3]; pInputStream = (BYTE*)pInputStream + stride; pVertexRegister++; } } //-----------------------------------------------------------------------------
// Based on register and data type the function computes FVF dword and presence
// bits:
// - Bits in the dwFVF2 are used to detect that some field is not entered twice
// - pnFloats is used to compute number of floats with position
//
// Bits for dwFVF2. Order is the same as in the FVF!!!
//
static const DWORD __POSITION_PRESENT = 1 << 0; static const DWORD __BLENDWEIGHT_PRESENT = 1 << 1; static const DWORD __BLENDINDICES_PRESENT = 1 << 2; static const DWORD __NORMAL_PRESENT = 1 << 3; static const DWORD __PSIZE_PRESENT = 1 << 4; static const DWORD __DIFFUSE_PRESENT = 1 << 5; static const DWORD __SPECULAR_PRESENT = 1 << 6; // __TEXTURE0_PRESENT must start from 8th bit
static const DWORD __TEXTURE0_PRESENT = 1 << 8; static const DWORD __TEXTURE1_PRESENT = 1 << 9; static const DWORD __TEXTURE2_PRESENT = 1 << 10; static const DWORD __TEXTURE3_PRESENT = 1 << 11; static const DWORD __TEXTURE4_PRESENT = 1 << 12; static const DWORD __TEXTURE5_PRESENT = 1 << 13; static const DWORD __TEXTURE6_PRESENT = 1 << 14; static const DWORD __TEXTURE7_PRESENT = 1 << 15; static const DWORD __POSITION2_PRESENT = 1 << 16; static const DWORD __NORMAL2_PRESENT = 1 << 17;
// Check if any bit left from the CurrentBit is set in PresenceBits
// PresenceBits are updated by CurrentBit.
//
inline void CheckOrder( DWORD* pPresenceBits, // Presence bits for the declaration
DWORD CurrentBit, BOOL* pFlag, // Out of order flag for the declaration
char* s) // Name of the field
{ if (*pPresenceBits & CurrentBit) { char msg[80]; sprintf(msg, "%s specified twice in the declaration", s); D3D_THROW_FAIL(msg); } if (*pPresenceBits & ~(CurrentBit | (CurrentBit-1))) { *pFlag = FALSE; } *pPresenceBits |= CurrentBit; }
void UpdateFVF(DWORD dwRegister, DWORD dwDataType, DWORD* pdwFVF, // FVF for the current declaration
DWORD* pdwFVF2, // Presence bits for the current stream
DWORD* pnFloats, BOOL* pbLegacyFVF) { switch (dwRegister) { case D3DVSDE_POSITION: if (dwDataType != D3DVSDT_FLOAT3) D3D_THROW_FAIL("Position register must be FLOAT3 for fixed-function pipeline");
CheckOrder(pdwFVF2, __POSITION_PRESENT, pbLegacyFVF, "Position"); *pdwFVF |= D3DFVF_XYZ; break; case D3DVSDE_POSITION2: if (dwDataType != D3DVSDT_FLOAT3) D3D_THROW_FAIL("Position2 register must be FLOAT3 for fixed-function pipeline"); CheckOrder(pdwFVF2, __POSITION2_PRESENT, pbLegacyFVF, "Position2"); break; case D3DVSDE_BLENDWEIGHT: { CheckOrder(pdwFVF2, __BLENDWEIGHT_PRESENT, pbLegacyFVF, "Blend weight"); switch (dwDataType) { case D3DVSDT_FLOAT1: (*pnFloats)++; break; case D3DVSDT_FLOAT2: (*pnFloats) += 2; break; case D3DVSDT_FLOAT3: (*pnFloats) += 3; break; case D3DVSDT_FLOAT4: (*pnFloats) += 4; break; default: D3D_THROW_FAIL("Invalid data type set for vertex blends"); break; } break; } case D3DVSDE_NORMAL: CheckOrder(pdwFVF2, __NORMAL_PRESENT, pbLegacyFVF, "Normal"); if (dwDataType != D3DVSDT_FLOAT3) D3D_THROW_FAIL("Normal register must be FLOAT3 for fixed-function pipeline"); *pdwFVF |= D3DFVF_NORMAL; break; case D3DVSDE_NORMAL2: CheckOrder(pdwFVF2, __NORMAL2_PRESENT, pbLegacyFVF, "Normal2"); if (dwDataType != D3DVSDT_FLOAT3) D3D_THROW_FAIL("Normal2 register must be FLOAT3 for fixed-function pipeline"); break; case D3DVSDE_PSIZE: CheckOrder(pdwFVF2, __PSIZE_PRESENT, pbLegacyFVF, "Point size"); if (dwDataType != D3DVSDT_FLOAT1) D3D_THROW_FAIL("Point size register must be FLOAT1 for fixed-function pipeline"); *pdwFVF |= D3DFVF_PSIZE; break; case D3DVSDE_DIFFUSE: CheckOrder(pdwFVF2, __DIFFUSE_PRESENT, pbLegacyFVF, "Diffuse"); if (dwDataType != D3DVSDT_D3DCOLOR) D3D_THROW_FAIL("Diffuse register must be D3DCOLOR for fixed-function pipeline"); *pdwFVF |= D3DFVF_DIFFUSE; break; case D3DVSDE_SPECULAR: CheckOrder(pdwFVF2, __SPECULAR_PRESENT, pbLegacyFVF, "Specular"); if (dwDataType != D3DVSDT_D3DCOLOR) D3D_THROW_FAIL("Specular register must be D3DCOLOR for fixed-function pipeline"); *pdwFVF |= D3DFVF_SPECULAR; break; case D3DVSDE_BLENDINDICES: CheckOrder(pdwFVF2, __BLENDINDICES_PRESENT, pbLegacyFVF, "Blend indices"); if (dwDataType != D3DVSDT_UBYTE4) D3D_THROW_FAIL("Blend indices register must be D3DVSDT_UBYTE4 for fixed-function pipeline"); // Update number of floats after position
(*pnFloats)++; break; case D3DVSDE_TEXCOORD0: case D3DVSDE_TEXCOORD1: case D3DVSDE_TEXCOORD2: case D3DVSDE_TEXCOORD3: case D3DVSDE_TEXCOORD4: case D3DVSDE_TEXCOORD5: case D3DVSDE_TEXCOORD6: case D3DVSDE_TEXCOORD7: { DWORD dwTextureIndex = dwRegister - D3DVSDE_TEXCOORD0; DWORD dwBit = __TEXTURE0_PRESENT << dwTextureIndex; CheckOrder(pdwFVF2, dwBit, pbLegacyFVF, "Texture"); switch (dwDataType) { case D3DVSDT_FLOAT1: *pdwFVF |= D3DFVF_TEXCOORDSIZE1(dwTextureIndex); break; case D3DVSDT_FLOAT2: *pdwFVF |= D3DFVF_TEXCOORDSIZE2(dwTextureIndex); break; case D3DVSDT_FLOAT3: *pdwFVF |= D3DFVF_TEXCOORDSIZE3(dwTextureIndex); break; case D3DVSDT_FLOAT4: *pdwFVF |= D3DFVF_TEXCOORDSIZE4(dwTextureIndex); break; default: D3D_THROW_FAIL("Invalid data type set for texture register"); break; } break; } default: D3D_THROW_FAIL("Invalid register set for fixed-function pipeline"); break; } } //-----------------------------------------------------------------------------
void CVStreamDecl::Parse(CD3DBase* pDevice, DWORD CONST ** ppToken, BOOL bFixedFunction, DWORD* pdwFVF, DWORD* pdwFVF2, DWORD* pnFloats, BOOL* pbLegacyFVF, UINT usage, BOOL bTessStream) { CONST DWORD* pToken = *ppToken; // Used to compute stream stride and offset in bytes for each stream element
DWORD dwCurrentOffset = 0; // FVF and FVF2 for this stream only. Used to check if data in the stream
// form a FVF subset
DWORD dwFVF2 = 0; DWORD dwFVF = 0; DWORD nFloats = 0; // Set to TRUE, if data in the stream is an FVF subset
BOOL bFVFSubset = TRUE; while (TRUE) { DWORD dwToken = *pToken++; const DWORD dwTokenType = D3DVSD_GETTOKENTYPE(dwToken); switch (dwTokenType) { case D3DVSD_TOKEN_NOP: break; case D3DVSD_TOKEN_TESSELLATOR: { *pbLegacyFVF = FALSE; bFVFSubset = FALSE; const DWORD dwDataType = D3DVSD_GETDATATYPE(dwToken); switch (dwDataType) { case D3DVSDT_FLOAT2: case D3DVSDT_FLOAT3: break; } break; } case D3DVSD_TOKEN_STREAMDATA: { switch (D3DVSD_GETDATALOADTYPE(dwToken)) { case D3DVSD_LOADREGISTER: { #if DBG
if (m_dwNumElements >= __NUMELEMENTS) { D3D_ERR("D3DVSD_TOKEN_STREAMDATA:"); D3D_ERR(" Number of vertex elements in a stream is greater than max supported"); D3D_ERR(" Max supported number of elements is %d", __NUMELEMENTS); D3D_THROW_FAIL(""); } #endif
CVElement* pElement = &m_Elements[m_dwNumElements++]; const DWORD dwDataType = D3DVSD_GETDATATYPE(dwToken); const DWORD dwRegister = D3DVSD_GETVERTEXREG(dwToken); pElement->m_dwOffset = dwCurrentOffset; pElement->m_dwRegister = dwRegister; pElement->m_dwDataType = dwDataType; switch (dwDataType) { case D3DVSDT_FLOAT1: dwCurrentOffset += sizeof(float); pElement->m_pfnCopy = (LPVOID)Copy_FLOAT1; break; case D3DVSDT_FLOAT2: dwCurrentOffset += sizeof(float) * 2; pElement->m_pfnCopy = (LPVOID)Copy_FLOAT2; break; case D3DVSDT_FLOAT3: dwCurrentOffset += sizeof(float) * 3; pElement->m_pfnCopy = (LPVOID)Copy_FLOAT3; break; case D3DVSDT_FLOAT4: dwCurrentOffset += sizeof(float) * 4; pElement->m_pfnCopy = (LPVOID)Copy_FLOAT4; break; case D3DVSDT_D3DCOLOR: dwCurrentOffset += sizeof(DWORD); pElement->m_pfnCopy = (LPVOID)Copy_D3DCOLOR; break; case D3DVSDT_UBYTE4: #if DBG
// Do not fail when software processing will be used
if (pDevice->GetD3DCaps()->VertexProcessingCaps & D3DVTXPCAPS_NO_VSDT_UBYTE4 && !((usage & D3DUSAGE_SOFTWAREPROCESSING && pDevice->BehaviorFlags() & D3DCREATE_MIXED_VERTEXPROCESSING) || (pDevice->BehaviorFlags() & D3DCREATE_SOFTWARE_VERTEXPROCESSING))) { D3D_THROW_FAIL("Device does not support UBYTE4 data type"); } #endif // DBG
dwCurrentOffset += sizeof(DWORD); pElement->m_pfnCopy = (LPVOID)Copy_UBYTE4; break; case D3DVSDT_SHORT2: dwCurrentOffset += sizeof(short) * 2; pElement->m_pfnCopy = (LPVOID)Copy_SHORT2; break; case D3DVSDT_SHORT4: dwCurrentOffset += sizeof(short) * 4; pElement->m_pfnCopy = (LPVOID)Copy_SHORT4; break; default: D3D_ERR("D3DVSD_TOKEN_STREAMDATA: Invalid element data type: %10x", dwToken); D3D_THROW_FAIL(""); } // Compute input FVF for fixed-function pipeline
if (bFixedFunction) { // Update FVF for the declaration
UpdateFVF(dwRegister, dwDataType, pdwFVF, pdwFVF2, pnFloats, pbLegacyFVF); // Update FVF for the stream
UpdateFVF(dwRegister, dwDataType, &dwFVF, &dwFVF2, &nFloats, &bFVFSubset); } else if (dwRegister >= D3DVS_INPUTREG_MAX_V1_1) D3D_THROW_FAIL("D3DVSD_TOKEN_STREAMDATA: Invalid register number"); break; } case D3DVSD_SKIP: { if (bFixedFunction) { D3D_THROW_FAIL("D3DVSD_SKIP is not allowed for fixed-function pipeline"); } const DWORD dwCount = D3DVSD_GETSKIPCOUNT(dwToken); dwCurrentOffset += dwCount * sizeof(DWORD); break; } default: D3D_ERR("Invalid data load type: %10x", dwToken); D3D_THROW_FAIL(""); } break; } default: { *ppToken = pToken - 1; m_dwStride = dwCurrentOffset; goto l_exit; } } // switch
} // while
l_exit: if (bFixedFunction && !bTessStream) { #if DBG
m_dwFVF = dwFVF; #endif
if (!bFVFSubset) { D3D_THROW_FAIL("For fixed-function pipeline each stream has to be an FVF subset"); } if (dwFVF2 & (__POSITION2_PRESENT | __NORMAL2_PRESENT | __PSIZE_PRESENT | __BLENDINDICES_PRESENT)) { *pbLegacyFVF = FALSE; } } } //-----------------------------------------------------------------------------
CVDeclaration::CVDeclaration(DWORD dwNumStreams) { m_pConstants = NULL; m_pConstantsTail = NULL; m_pActiveStreams = NULL; m_pActiveStreamsTail = NULL; m_dwInputFVF = 0; m_bLegacyFVF = TRUE; m_dwNumStreams = dwNumStreams; m_bStreamTessPresent = FALSE; } //-----------------------------------------------------------------------------
CVDeclaration::~CVDeclaration() { delete m_pActiveStreams; delete m_pConstants; } //-----------------------------------------------------------------------------
void CVDeclaration::Parse(CD3DBase* pDevice, CONST DWORD* pTok, BOOL bFixedFunction, DWORD* pDeclSize, UINT usage) { DWORD dwFVF = 0; // FVF for fixed-function pipeline
DWORD dwFVF2 = 0; // Texture presence bits (8 bits)
DWORD nFloats = 0; // Number of floats after position
DWORD dwStreamPresent = 0; // Bit is set if a stream is used
m_bLegacyFVF = TRUE;
CONST DWORD* pToken = pTok; while (TRUE) { DWORD dwToken = *pToken++; const DWORD dwTokenType = D3DVSD_GETTOKENTYPE(dwToken); switch (dwTokenType) { case D3DVSD_TOKEN_NOP: break; case D3DVSD_TOKEN_STREAM: { CVStreamDecl StreamTess;
if( D3DVSD_ISSTREAMTESS(dwToken) ) { m_bLegacyFVF = FALSE; if( m_bStreamTessPresent ) { D3D_THROW(D3DERR_INVALIDCALL, "Tesselator Stream has already been defined in the declaration"); }
m_bStreamTessPresent = TRUE; //
// For now simply skip over the Tess tokens in the
// Runtime.
StreamTess.Parse(pDevice, &pToken, bFixedFunction, &dwFVF, &dwFVF2, &nFloats, &m_bLegacyFVF, usage, TRUE); } else { DWORD dwStream = D3DVSD_GETSTREAMNUMBER(dwToken); if (dwStream >= m_dwNumStreams) { D3D_THROW_FAIL("Stream number is too big"); }
if (dwStreamPresent & (1 << dwStream)) { D3D_THROW(D3DERR_INVALIDCALL, "Stream is already defined" "in the declaration"); }
dwStreamPresent |= 1 << dwStream;
// There are more than one stream present, so cant be
// handled by legacy FVF.
if( dwStreamPresent & (dwStreamPresent - 1) ) m_bLegacyFVF = FALSE;
CVStreamDecl* pStream = new CVStreamDecl; if (pStream == NULL) { D3D_THROW(E_OUTOFMEMORY, "Not enough memory"); } try { pStream->Parse(pDevice, &pToken, bFixedFunction, &dwFVF, &dwFVF2, &nFloats, &m_bLegacyFVF, usage); pStream->m_dwStreamIndex = dwStream; if (m_pActiveStreams == NULL) { m_pActiveStreams = pStream; m_pActiveStreamsTail = pStream; } else { m_pActiveStreamsTail->Append(pStream); m_pActiveStreamsTail = pStream; } } catch (HRESULT e) { delete pStream; throw e; } } break; } case D3DVSD_TOKEN_STREAMDATA: { D3D_THROW_FAIL("D3DVSD_TOKEN_STREAMDATA could only be used after D3DVSD_TOKEN_STREAM"); } case D3DVSD_TOKEN_CONSTMEM: { CVConstantData * cd = new CVConstantData; CheckForNull(cd, __LINE__, __FILE__);
cd->m_dwCount = D3DVSD_GETCONSTCOUNT(dwToken); cd->m_dwAddress = D3DVSD_GETCONSTADDRESS(dwToken);
UINT ValidationCount; if (usage & D3DUSAGE_SOFTWAREPROCESSING) ValidationCount = D3DVS_CONSTREG_MAX_V1_1; else ValidationCount = pDevice->GetD3DCaps()->MaxVertexShaderConst;
if ((cd->m_dwCount + cd->m_dwAddress) > ValidationCount) D3D_THROW_FAIL("D3DVSD_TOKEN_CONSTMEM writes outside constant memory");
const DWORD dwSize = cd->m_dwCount << 2; // number of DWORDs
cd->m_pData = new DWORD[dwSize]; CheckForNull(cd->m_pData, __LINE__, __FILE__);
memcpy(cd->m_pData, pToken, dwSize << 2); if (m_pConstants == NULL) { m_pConstants = cd; m_pConstantsTail = cd; } else { m_pConstantsTail->Append(cd); m_pConstantsTail = cd; } pToken += dwSize; break; } case D3DVSD_TOKEN_EXT: { // Skip extension info
DWORD dwCount = D3DVSD_GETEXTCOUNT(dwToken); pToken += dwCount; break; } case D3DVSD_TOKEN_END: { goto l_End; } default: { D3D_ERR("Invalid declaration token: %10x", dwToken); D3D_THROW_FAIL(""); } } } l_End: // Validate input for the fixed-function pipeline
if (bFixedFunction && !m_bStreamTessPresent) { m_dwInputFVF = dwFVF & 0xFFFF0FFF; // Remove float count
switch (nFloats) { case 0: m_dwInputFVF |= D3DFVF_XYZ; break; case 1: m_dwInputFVF |= D3DFVF_XYZB1; break; case 2: m_dwInputFVF |= D3DFVF_XYZB2; break; case 3: m_dwInputFVF |= D3DFVF_XYZB3; break; case 4: m_dwInputFVF |= D3DFVF_XYZB4; break; case 5: m_dwInputFVF |= D3DFVF_XYZB5; break; default: D3D_THROW_FAIL("Too many floats after position"); } // Compute number of texture coordinates
DWORD nTexCoord = 0; DWORD dwTexturePresenceBits = (dwFVF2 >> 8) & 0xFF; while (dwTexturePresenceBits & 1) { dwTexturePresenceBits >>= 1; nTexCoord++; } // There should be no gaps in texture coordinates
if (dwTexturePresenceBits) D3D_THROW_FAIL("Texture coordinates should have no gaps");
m_dwInputFVF |= nTexCoord << D3DFVF_TEXCOUNT_SHIFT;
// Position must be set
if ((dwFVF & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) D3D_THROW_FAIL("Position register must be set"); } if (pDeclSize != NULL) { *pDeclSize = (DWORD) (pToken - pTok) << 2; } } //---------------------------------------------------------------------
CVStream::~CVStream() { if (m_pVB) m_pVB->DecrementUseCount(); } //---------------------------------------------------------------------
CVIndexStream::~CVIndexStream() { if (m_pVBI) m_pVBI->DecrementUseCount(); } //---------------------------------------------------------------------
DWORD g_PrimToVerCount[7][2] = { {0, 0}, // Illegal
{1, 0}, // D3DPT_POINTLIST = 1,
{2, 0}, // D3DPT_LINELIST = 2,
{1, 1}, // D3DPT_LINESTRIP = 3,
{3, 0}, // D3DPT_TRIANGLELIST = 4,
{1, 2}, // D3DPT_TRIANGLESTRIP = 5,
{1, 2}, // D3DPT_TRIANGLEFAN = 6,
}; //-----------------------------------------------------------------------------
HRESULT D3DFE_PVFUNCSI::CreateShader(CVElement* pElements, DWORD dwNumElements, DWORD* pdwShaderCode, DWORD dwOutputFVF, CPSGPShader** ppPSGPShader) { *ppPSGPShader = NULL; try { *ppPSGPShader = m_VertexVM.CreateShader(pElements, dwNumElements, pdwShaderCode); if (*ppPSGPShader == NULL) return D3DERR_INVALIDCALL; } D3D_CATCH; return D3D_OK; } //-----------------------------------------------------------------------------
HRESULT D3DFE_PVFUNCSI::SetActiveShader(CPSGPShader* pPSGPShader) { return m_VertexVM.SetActiveShader((CVShaderCode*)pPSGPShader); } //-----------------------------------------------------------------------------
// Load vertex shader constants
HRESULT D3DFE_PVFUNCSI::LoadShaderConstants(DWORD start, DWORD count, LPVOID buffer) { return m_VertexVM.SetData(D3DSPR_CONST, start, count, buffer); } //-----------------------------------------------------------------------------
// Get vertex shader constants
HRESULT D3DFE_PVFUNCSI::GetShaderConstants(DWORD start, DWORD count, LPVOID buffer) { return m_VertexVM.GetData(D3DSPR_CONST, start, count, buffer); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::GetVertexShaderConstant"
HRESULT D3DAPI CD3DHal::GetVertexShaderConstant(DWORD Register, LPVOID pData, DWORD count) { API_ENTER(this); #if DBG
// Validate Parameters
if (!VALID_WRITEPTR(pData, 4 * sizeof(DWORD) * count)) { D3D_ERR("Invalid constant data pointer. GetVertexShaderConstant failed."); return D3DERR_INVALIDCALL; } if ((GetD3DCaps()->VertexShaderVersion == D3DVS_VERSION(0,0)) && (BehaviorFlags() & (D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE))) { D3D_ERR("No programmable vertex shaders are supported by this device. GetVertexShaderConstant failed."); return D3DERR_INVALIDCALL; } UINT ValidationCount; if (BehaviorFlags() & D3DCREATE_MIXED_VERTEXPROCESSING) ValidationCount = max(m_MaxVertexShaderConst, D3DVS_CONSTREG_MAX_V1_1); else if (BehaviorFlags() & D3DCREATE_SOFTWARE_VERTEXPROCESSING) ValidationCount = D3DVS_CONSTREG_MAX_V1_1; else ValidationCount = m_MaxVertexShaderConst; if((Register + count) > ValidationCount) { D3D_ERR("Not that many constant registers in the vertex machine. GetVertexShaderConstant failed."); return D3DERR_INVALIDCALL; } #endif
HRESULT hr; if (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING || ((count + Register) <= D3DVS_CONSTREG_MAX_V1_1)) { // For software vertex processing we store constant registers in PSGP if
// possible
return m_pv->pGeometryFuncs->GetShaderConstants(Register, count, const_cast<VOID*>(pData)); } else { if (Register >= D3DVS_CONSTREG_MAX_V1_1) { // When all modified registers are above software limit, we use Microsoft
// internal array
hr = GeometryFuncsGuaranteed->GetShaderConstants(Register, count, const_cast<VOID*>(pData)); } else { // Part of constant data is taken from PSGP array and part from
// Microsoft's array
UINT FirstCount = D3DVS_CONSTREG_MAX_V1_1 - Register; hr = m_pv->pGeometryFuncs->GetShaderConstants(Register, FirstCount, const_cast<VOID*>(pData)); if (FAILED(hr)) { return hr; } return GeometryFuncsGuaranteed->GetShaderConstants(D3DVS_CONSTREG_MAX_V1_1, Register + count - D3DVS_CONSTREG_MAX_V1_1, &((DWORD*)pData)[FirstCount*4]); } return hr; } return m_pv->pGeometryFuncs->GetShaderConstants(Register, count, pData); } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::GetVertexShader"
HRESULT D3DAPI CD3DHal::GetVertexShader(LPDWORD pdwHandle) { API_ENTER(this); // Takes D3D Lock if necessary
HRESULT ret = D3D_OK; #if DBG
// Validate Parameters
if (!VALID_WRITEPTR(pdwHandle, sizeof(DWORD))) { D3D_ERR("Invalid handle pointer. GetVertexShader failed."); return D3DERR_INVALIDCALL; } #endif
*pdwHandle = m_dwCurrentShaderHandle; return ret; } //-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::GetPixelShader"
HRESULT D3DAPI CD3DHal::GetPixelShader(LPDWORD pdwHandle) { API_ENTER(this); // Takes D3D Lock if necessary
HRESULT ret = D3D_OK;
#if DBG
// Validate Parameters
if (!VALID_WRITEPTR(pdwHandle, sizeof(DWORD))) { D3D_ERR("Invalid handle pointer. GetPixelShader failed."); return D3DERR_INVALIDCALL; } #endif
*pdwHandle = m_dwCurrentPixelShaderHandle; return ret; } #if DBG
//-----------------------------------------------------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CD3DHal::ValidateRTPatch"
void CD3DHal::ValidateRTPatch() { if (D3DVSD_ISLEGACY(m_dwCurrentShaderHandle)) { if (m_pStream[0].m_pVB == 0) { D3D_THROW_FAIL("Draw[RT]Patch should have streams set"); } if ((m_pStream[0].m_pVB->GetBufferDesc()->Usage & D3DUSAGE_RTPATCHES) == 0) { D3D_THROW_FAIL("Vertex buffers used for rendering RT-Patches should have D3DUSAGE_RTPATCHES set"); } } else { CVStreamDecl* pStream; pStream = m_pCurrentShader->m_Declaration.m_pActiveStreams; while(pStream) { UINT index = pStream->m_dwStreamIndex; CVStream* pDeviceStream = &m_pStream[index]; if (pDeviceStream->m_pVB == 0) { D3D_THROW_FAIL("Draw[RT]Patch should have streams set"); } if ((pDeviceStream->m_pVB->GetBufferDesc()->Usage & D3DUSAGE_RTPATCHES) == 0) { D3D_THROW_FAIL("Vertex buffers used for rendering RT-Patches should have D3DUSAGE_RTPATCHES set"); } pStream = (CVStreamDecl*)pStream->m_pNext; } } } #endif // DBG
|