/*==========================================================================; * * Copyright (C) 1997 Microsoft Corporation. All Rights Reserved. * * File: devstate.c * Content: device state management * ***************************************************************************/ #include "pch.cpp" #pragma hdrstop #include "drawprim.hpp" #include "pvvid.h" #include "ddibase.h" //--------------------------------------------------------------------- #if DBG void CPackedBitArray::CheckIndex(UINT index) { if (index >= m_size) { D3D_THROW_FAIL("Invalid index"); } } #endif // DBG //--------------------------------------------------------------------- inline void UpdateFogFactor(D3DFE_PROCESSVERTICES* lpDevI) { if (lpDevI->lighting.fog_end == lpDevI->lighting.fog_start) lpDevI->lighting.fog_factor = D3DVAL(0.0); else lpDevI->lighting.fog_factor = D3DVAL(255) / (lpDevI->lighting.fog_end - lpDevI->lighting.fog_start); } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::SetRenderState" HRESULT D3DAPI CD3DHal::SetRenderState(D3DRENDERSTATETYPE dwState, DWORD value) { API_ENTER(this); // Takes D3D Lock if necessary #if DBG if (dwState >= D3D_MAXRENDERSTATES || dwState == 0 ) { D3D_ERR( "Invalid render state type. SetRenderState failed." ); return D3DERR_INVALIDCALL; } #endif try { if (this->m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE) { if(this->CheckForRetiredRenderState(dwState)) { m_pStateSets->InsertRenderState(dwState, value, CanHandleRenderState(dwState)); } else { D3D_ERR("Invalid renderstate %d. SetRenderState failed.", dwState); return D3DERR_INVALIDCALL; } } else this->SetRenderStateFast(dwState, value); return D3D_OK; } catch(HRESULT ret) { D3D_ERR("SetRenderState failed."); return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::SetRenderStateFast" HRESULT D3DAPI CD3DHal::SetRenderStateFast(D3DRENDERSTATETYPE dwState, DWORD value) { // NOTE: This can become a public API through the // v-table hack. This should only happen for // single-threaded apps; so we don't need // to take the critical section. // API_ENTER(this); // Takes D3D Lock if necessary #if DBG if (dwState >= D3D_MAXRENDERSTATES || dwState == 0 ) { D3D_ERR( "Invalid render state type. SetRenderState failed." ); return D3DERR_INVALIDCALL; } #endif if (!rsVec.IsBitSet(dwState)) { // Fast path. We do not need any processing done in UpdateInternalState // other than updating rstates array if ( (this->rstates[dwState] == value) #if DBG && (dwState != D3DRS_DEBUGMONITORTOKEN) // don't filter these #endif ) { D3D_WARN(4,"Ignoring redundant SetRenderState - %d", dwState); return D3D_OK; } this->rstates[dwState] = value; // Output state to the device driver try { m_pDDI->SetRenderState(dwState, value); } catch(HRESULT ret) { D3D_ERR("SetRenderState failed."); return ret; } } else { try { // Wrap modes could be re-programmed. We need to restore them before // filtering redundant values if (m_pv->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { RestoreTextureStages(this); ForceFVFRecompute(); } if ( (this->rstates[dwState] == value) #if DBG && (dwState != D3DRS_DEBUGMONITORTOKEN) // don't filter these #endif ) { D3D_WARN(4,"Ignoring redundant SetRenderState - %d", dwState); return D3D_OK; } this->UpdateInternalState(dwState, value); // Vertex processing only render states will be passed to the // driver when we switch to the hardware vertex processing mode if ((!(rsVertexProcessingOnly.IsBitSet(dwState) && m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING))) { if (CanHandleRenderState(dwState)) { #if DBG if(!CheckForRetiredRenderState(dwState)) { D3D_ERR("Invalid (old) renderstate %d. SetRenderState failed.", dwState); return D3DERR_INVALIDCALL; } #endif // DBG m_pDDI->SetRenderState(dwState, value); } } } catch(HRESULT ret) { D3D_ERR("SetRenderState failed."); return ret; } } return D3D_OK; } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::SetRenderStateInternal" void CD3DHal::SetRenderStateInternal(D3DRENDERSTATETYPE dwState, DWORD dwValue) { if (this->rstates[dwState] == dwValue) { D3D_WARN(4,"Ignoring redundant SetRenderState - %d", dwState); return; } this->UpdateInternalState(dwState, dwValue); if (CanHandleRenderState(dwState)) m_pDDI->SetRenderState(dwState, dwValue); } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice::GetRenderState" HRESULT D3DAPI CD3DHal::GetRenderState(D3DRENDERSTATETYPE dwState, LPDWORD lpdwValue) { API_ENTER(this); // Takes D3D Lock if necessary #if DBG if (dwState >= D3D_MAXRENDERSTATES || dwState == 0) { D3D_ERR( "Invalid render state value. GetRenderState failed." ); return D3DERR_INVALIDCALL; } #endif if (!VALID_WRITEPTR(lpdwValue, sizeof(DWORD))) { D3D_ERR( "Invalid DWORD pointer. GetRenderState failed." ); return D3DERR_INVALIDCALL; } if(!CheckForRetiredRenderState(dwState)) { D3D_ERR("invalid renderstate %d. GetRenderState failed.", dwState); return D3DERR_INVALIDCALL; } // WRAP render states could be re-mapped so we have to return the original // value if (dwState >= D3DRENDERSTATE_WRAP0 && dwState <= D3DRENDERSTATE_WRAP7) { if (m_pv->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { DWORD dwTexCoordIndex = dwState - D3DRENDERSTATE_WRAP0; for (DWORD i=0; i < this->dwNumTextureStagesToRemap; i++) { LPD3DFE_TEXTURESTAGE pStage = &this->textureStageToRemap[i]; if (pStage->dwInpCoordIndex == dwTexCoordIndex) { if (pStage->dwInpCoordIndex != pStage->dwOutCoordIndex) { *lpdwValue = pStage->dwOrgWrapMode; return D3D_OK; } } } } } *lpdwValue = this->rstates[dwState]; return D3D_OK; } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::SetTextureStageState" HRESULT D3DAPI CD3DHal::SetTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, DWORD dwValue) { API_ENTER(this); // Takes D3D Lock if necessary #if DBG if ( (dwStage >= D3DHAL_TSS_MAXSTAGES) || (dwState == 0) || (dwState >= D3DTSS_MAX) || (dwState == 12) ) // D3DTSS_ADDRESS no longer valid { D3D_ERR( "Invalid texture stage or state index. SetTextureStageState failed." ); return D3DERR_INVALIDCALL; } #endif //DBG try { if (this->m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE) { m_pStateSets->InsertTextureStageState(dwStage, dwState, dwValue); return D3D_OK; } return this->SetTextureStageStateFast(dwStage, dwState, dwValue); } catch(HRESULT ret) { D3D_ERR("SetTextureStageState failed."); return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::SetTextureStageStateFast" HRESULT D3DAPI CD3DHal::SetTextureStageStateFast(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, DWORD dwValue) { // NOTE: This can become a public API through the // v-table hack. This should only happen for // single-threaded apps; so we don't need // to take the critical section. // API_ENTER(this); // Takes D3D Lock if necessary #if DBG if ( (dwStage >= D3DHAL_TSS_MAXSTAGES) || (dwState == 0) || (dwState >= D3DTSS_MAX) || (dwState == 12) ) // D3DTSS_ADDRESS no longer valid { D3D_ERR( "Invalid texture stage or state index. SetTextureStageState failed." ); return D3DERR_INVALIDCALL; } #endif //DBG // Fast path. We do not need any processing done in UpdateInternalTSS other than updating tsstates array if (NeedInternalTSSUpdate(dwState)) { // Texture stages could be re-programmed. We need to restore them before // filtering redundant values if (m_pv->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { RestoreTextureStages(this); ForceFVFRecompute(); } if (this->tsstates[dwStage][dwState] == dwValue) { D3D_WARN(4,"Ignoring redundant SetTextureStageState. Stage: %d, State: %d", dwStage, dwState); return D3D_OK; } if(this->UpdateInternalTextureStageState(dwStage, dwState, &dwValue)) return D3D_OK; } else { if (this->tsstates[dwStage][dwState] == dwValue) { D3D_WARN(4,"Ignoring redundant SetTextureStageState. Stage: %d, State: %d", dwStage, dwState); return D3D_OK; } tsstates[dwStage][dwState] = dwValue; } if (dwStage >= m_dwMaxTextureBlendStages) return D3D_OK; try { m_pDDI->SetTSS(dwStage, dwState, dwValue); } catch (HRESULT ret) { D3D_ERR("SetTextureStageState failed."); return ret; } return D3D_OK; } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice::GetTextureStageState" HRESULT D3DAPI CD3DHal::GetTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, LPDWORD pdwValue) { API_ENTER(this); // Takes D3D Lock if necessary #if DBG if ( (dwStage >= D3DHAL_TSS_MAXSTAGES) || (dwState == 0) || (dwState >= D3DTSS_MAX) || (dwState == 12) ) // D3DTSS_ADDRESS no longer valid { D3D_ERR( "Invalid texture stage or state index. GetTextureStageState failed." ); return D3DERR_INVALIDCALL; } #endif //DBG if (!VALID_WRITEPTR(pdwValue, sizeof(DWORD))) { D3D_ERR( "Invalid DWORD pointer. GetTextureStageState failed." ); return D3DERR_INVALIDCALL; } // If texture indices were re-mapped we have to find and return the original value if (dwState == D3DTSS_TEXCOORDINDEX && m_pv->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { RestoreTextureStages(this); ForceFVFRecompute(); } // Don't bother to check for DX6 support, just return the // cached value. *pdwValue = tsstates[dwStage][dwState]; return D3D_OK; } #ifdef FAST_PATH //----------------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::SetVertexShaderFast" HRESULT D3DAPI CD3DHal::SetVertexShaderFast(DWORD dwHandle) { try { #if DBG CheckVertexShaderHandle(dwHandle); DebugStateChanged( D3DDM_SC_VSSETSHADER ); #endif DXGASSERT((m_dwRuntimeFlags & (D3DRT_RECORDSTATEMODE | D3DRT_RSSOFTWAREPROCESSING)) == 0 && (BehaviorFlags() & D3DCREATE_MULTITHREADED) == 0); // We need to set m_pCurrentShader becausu we do NPatch emulation in // hardware vertex processing mode static_cast(this)->m_pCurrentShader = NULL; CVConstantData* pConst = NULL; #if DBG m_pv->dwDeviceFlags &= ~D3DDEV_VERTEXSHADERS; #endif if (!D3DVSD_ISLEGACY(dwHandle)) { static_cast(this)->m_pCurrentShader = (CVShader*)m_pVShaderArray->GetObject(dwHandle); CVShader* pShader = (CVShader*)m_pVShaderArray->GetObjectFast(dwHandle); pConst = pShader->m_Declaration.m_pConstants; #ifdef DBG if(!(pShader->m_dwFlags & CVShader::FIXEDFUNCTION)) { // Programmable pipeline is used m_pv->dwDeviceFlags |= D3DDEV_VERTEXSHADERS; } #endif } // We can return earlier when we do not need to update constants if (pConst == NULL) { if (dwHandle == m_dwCurrentShaderHandle) return S_OK; } else // Update our copy of constants for Get() 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_dwCurrentShaderHandle = dwHandle; if (!(m_dwRuntimeFlags & D3DRT_EXECUTESTATEMODE)) { m_pDDI->SetVertexShaderHW(dwHandle); } if (!IS_DX8HAL_DEVICE(this)) { PickDrawPrimFn(); } } catch(HRESULT hr) { D3D_ERR("SetVertexShader failed."); ClearVertexShaderHandle(); return hr; } return S_OK; } #endif // FAST_PATH //---------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::SetTransformI" void CD3DHal::SetTransformI(D3DTRANSFORMSTATETYPE state, CONST D3DMATRIX* lpMat) { if ((DWORD)state >= __WORLDMATRIXBASE && (DWORD)state < (__WORLDMATRIXBASE + __MAXWORLDMATRICES)) { // World matrix is set UINT index = (DWORD)state - __WORLDMATRIXBASE; *(LPD3DMATRIX)&m_pv->world[index] = *lpMat; if (index == 0) this->dwFEFlags |= D3DFE_WORLDMATRIX_DIRTY | D3DFE_FRONTEND_DIRTY; } else switch (state) { case D3DTS_VIEW : *(D3DMATRIX*)&m_pv->view = *lpMat; this->dwFEFlags |= D3DFE_VIEWMATRIX_DIRTY | D3DFE_FRONTEND_DIRTY; break; case D3DTS_PROJECTION : *(D3DMATRIX*)&this->transform.proj = *lpMat; this->dwFEFlags |= D3DFE_PROJMATRIX_DIRTY | D3DFE_FRONTEND_DIRTY; break; case D3DTS_TEXTURE0: case D3DTS_TEXTURE1: case D3DTS_TEXTURE2: case D3DTS_TEXTURE3: case D3DTS_TEXTURE4: case D3DTS_TEXTURE5: case D3DTS_TEXTURE6: case D3DTS_TEXTURE7: { m_pv->dwDeviceFlags |= D3DDEV_TEXTRANSFORMDIRTY; DWORD dwIndex = state - D3DTS_TEXTURE0; *(D3DMATRIX*)&m_pv->mTexture[dwIndex] = *lpMat; break; } } m_pv->MatrixStateCount++; if (!(m_dwRuntimeFlags & D3DRT_EXECUTESTATEMODE)) { if (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) this->pMatrixDirtyForDDI->SetBit(state); else m_pDDI->SetTransform(state, lpMat); // W range should always be updated if (state == D3DTS_PROJECTION) m_pDDI->UpdateWInfo(lpMat); } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::GetTransform" HRESULT D3DAPI CD3DHal::GetTransform(D3DTRANSFORMSTATETYPE state, LPD3DMATRIX lpMat) { API_ENTER(this); // Takes D3D Lock if necessary HRESULT ret = D3D_OK; #if DBG if (!VALID_WRITEPTR(lpMat, sizeof(D3DMATRIX))) { D3D_ERR( "Invalid matrix pointer. GetTransform failed." ); return D3DERR_INVALIDCALL; } #endif if ((DWORD)state >= __WORLDMATRIXBASE && (DWORD)state < (__WORLDMATRIXBASE + __MAXWORLDMATRICES)) { // World matrix is set UINT index = (DWORD)state - __WORLDMATRIXBASE; *lpMat = *(LPD3DMATRIX)&m_pv->world[index]; } else switch (state) { case D3DTS_VIEW : *lpMat = *(LPD3DMATRIX)&m_pv->view._11; break; case D3DTS_PROJECTION : *lpMat = *(LPD3DMATRIX)&this->transform.proj._11; break; case D3DTS_TEXTURE0: case D3DTS_TEXTURE1: case D3DTS_TEXTURE2: case D3DTS_TEXTURE3: case D3DTS_TEXTURE4: case D3DTS_TEXTURE5: case D3DTS_TEXTURE6: case D3DTS_TEXTURE7: *lpMat = *(LPD3DMATRIX)&m_pv->mTexture[state-D3DTS_TEXTURE0]._11; break; default : D3D_ERR( "Invalid state value passed to GetTransform. GetTransform failed." ); ret = D3DERR_INVALIDCALL; /* Work Item: Generate new meaningful return code */ break; } return ret; } // end of D3DDev2_GetTransform() //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::UpdateDriverStates" void CD3DHal::UpdateDriverStates() { // note we can't do a loop from 1 to D3DHAL_MAX_RSTATES(256) as some of // rstates are not valid states, passin them down to drivers(like // voodoo2 DX6 driver) will crash. static D3DRENDERSTATETYPE dx6states[] = { D3DRENDERSTATE_SPECULARENABLE, D3DRENDERSTATE_ZENABLE, D3DRENDERSTATE_FILLMODE, D3DRENDERSTATE_SHADEMODE, D3DRENDERSTATE_LINEPATTERN, D3DRENDERSTATE_ZWRITEENABLE, D3DRENDERSTATE_ALPHATESTENABLE, D3DRENDERSTATE_LASTPIXEL, D3DRENDERSTATE_SRCBLEND, D3DRENDERSTATE_DESTBLEND, D3DRENDERSTATE_CULLMODE, D3DRENDERSTATE_ZFUNC, D3DRENDERSTATE_ALPHAREF, D3DRENDERSTATE_ALPHAFUNC, D3DRENDERSTATE_DITHERENABLE, D3DRENDERSTATE_FOGENABLE, D3DRENDERSTATE_ZVISIBLE, D3DRENDERSTATE_STIPPLEDALPHA, D3DRENDERSTATE_FOGCOLOR, D3DRENDERSTATE_FOGTABLEMODE, D3DRENDERSTATE_FOGSTART, D3DRENDERSTATE_FOGEND, D3DRENDERSTATE_FOGDENSITY, D3DRENDERSTATE_COLORKEYENABLE, D3DRENDERSTATE_ALPHABLENDENABLE, D3DRENDERSTATE_ZBIAS, D3DRENDERSTATE_RANGEFOGENABLE, D3DRENDERSTATE_STIPPLEENABLE, D3DRENDERSTATE_MONOENABLE, D3DRENDERSTATE_ROP2, D3DRENDERSTATE_PLANEMASK, D3DRENDERSTATE_WRAPU, D3DRENDERSTATE_WRAPV, D3DRENDERSTATE_ANTIALIAS, D3DRENDERSTATE_SUBPIXEL, D3DRENDERSTATE_SUBPIXELX, D3DRENDERSTATE_EDGEANTIALIAS, D3DRENDERSTATE_STIPPLEPATTERN00, D3DRENDERSTATE_STIPPLEPATTERN01, D3DRENDERSTATE_STIPPLEPATTERN02, D3DRENDERSTATE_STIPPLEPATTERN03, D3DRENDERSTATE_STIPPLEPATTERN04, D3DRENDERSTATE_STIPPLEPATTERN05, D3DRENDERSTATE_STIPPLEPATTERN06, D3DRENDERSTATE_STIPPLEPATTERN07, D3DRENDERSTATE_STIPPLEPATTERN08, D3DRENDERSTATE_STIPPLEPATTERN09, D3DRENDERSTATE_STIPPLEPATTERN10, D3DRENDERSTATE_STIPPLEPATTERN11, D3DRENDERSTATE_STIPPLEPATTERN12, D3DRENDERSTATE_STIPPLEPATTERN13, D3DRENDERSTATE_STIPPLEPATTERN14, D3DRENDERSTATE_STIPPLEPATTERN15, D3DRENDERSTATE_STIPPLEPATTERN16, D3DRENDERSTATE_STIPPLEPATTERN17, D3DRENDERSTATE_STIPPLEPATTERN18, D3DRENDERSTATE_STIPPLEPATTERN19, D3DRENDERSTATE_STIPPLEPATTERN20, D3DRENDERSTATE_STIPPLEPATTERN21, D3DRENDERSTATE_STIPPLEPATTERN22, D3DRENDERSTATE_STIPPLEPATTERN23, D3DRENDERSTATE_STIPPLEPATTERN24, D3DRENDERSTATE_STIPPLEPATTERN25, D3DRENDERSTATE_STIPPLEPATTERN26, D3DRENDERSTATE_STIPPLEPATTERN27, D3DRENDERSTATE_STIPPLEPATTERN28, D3DRENDERSTATE_STIPPLEPATTERN29, D3DRENDERSTATE_STIPPLEPATTERN30, D3DRENDERSTATE_STIPPLEPATTERN31, D3DRENDERSTATE_TEXTUREPERSPECTIVE, D3DRENDERSTATE_STENCILENABLE, D3DRENDERSTATE_STENCILFAIL, D3DRENDERSTATE_STENCILZFAIL, D3DRENDERSTATE_STENCILPASS, D3DRENDERSTATE_STENCILFUNC, D3DRENDERSTATE_STENCILREF, D3DRENDERSTATE_STENCILMASK, D3DRENDERSTATE_STENCILWRITEMASK, D3DRENDERSTATE_TEXTUREFACTOR, D3DRENDERSTATE_WRAP0, D3DRENDERSTATE_WRAP1, D3DRENDERSTATE_WRAP2, D3DRENDERSTATE_WRAP3, D3DRENDERSTATE_WRAP4, D3DRENDERSTATE_WRAP5, D3DRENDERSTATE_WRAP6, D3DRENDERSTATE_WRAP7 }; HRESULT ret; for (DWORD i=0; iSetRenderState( dx6states[i], rstates[dx6states[i]] ); } for( i = 0; i < m_dwMaxTextureBlendStages; i++ ) { for( DWORD j = D3DTSS_COLOROP ; j < D3DTSS_TEXTURETRANSFORMFLAGS; ++j ) { m_pDDI->SetTSS( i, (D3DTEXTURESTAGESTATETYPE)j, this->tsstates[i][j] ); } } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::SetClipStatus" HRESULT D3DAPI CD3DHal::SetClipStatus(CONST D3DCLIPSTATUS8* status) { API_ENTER(this); // Takes D3D Lock if necessary #if DBG if (!VALID_PTR(status, sizeof(D3DCLIPSTATUS8)) ) { D3D_ERR( "Invalid status pointer. SetClipStatus failed." ); return D3DERR_INVALIDCALL; } #endif m_ClipStatus = * status; return D3D_OK; } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice::GetClipStatus" HRESULT D3DAPI CD3DHal::GetClipStatus(D3DCLIPSTATUS8* status) { API_ENTER(this); // Takes D3D Lock if necessary #if DBG if (! VALID_WRITEPTR(status, sizeof(D3DCLIPSTATUS8)) ) { D3D_ERR( "Invalid status pointer. GetClipStatus failed." ); return D3DERR_INVALIDCALL; } #endif *status = m_ClipStatus; return D3D_OK; } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::SwitchVertexProcessingMode" void CD3DHal::SwitchVertexProcessingMode(DWORD SoftwareMode) { m_pDDI->FlushStates(FALSE); // Invalidate all streams // What if a vertex buffer is batched? CVStream* pStream = m_pStream; for (UINT i=0; i < __NUMSTREAMS; i++) { pStream->m_pData = NULL; if (pStream->m_pVB) { m_pDDI->VBReleased(pStream->m_pVB); pStream->m_pVB->DecrementUseCount(); pStream->m_pVB = NULL; } pStream++; } m_pIndexStream->m_pData = NULL; if (m_pIndexStream->m_pVBI) { m_pDDI->VBIReleased(m_pIndexStream->m_pVBI); m_pIndexStream->m_pVBI->DecrementUseCount(); m_pIndexStream->m_pVBI = NULL; } ClearVertexShaderHandle(); m_pCurrentShader = NULL; // Setup capabilities if (SoftwareMode) { m_MaxVertexShaderConst = D3DVS_CONSTREG_MAX_V1_1; m_dwRuntimeFlags |= D3DRT_RSSOFTWAREPROCESSING; m_dwNumStreams = __NUMSTREAMS; m_dwMaxUserClipPlanes = __MAXUSERCLIPPLANES; #ifdef FAST_PATH FastPathSetVertexShaderSlow(); FastPathSetStreamSourceSlow(); FastPathSetIndicesSlow(); #endif // FAST_PATH } else { // We are switching from the software to the hardware mode m_dwRuntimeFlags &= ~D3DRT_RSSOFTWAREPROCESSING; #ifdef FAST_PATH FastPathSetVertexShaderFast(); FastPathSetStreamSourceFast(); FastPathSetIndicesFast(); #endif // FAST_PATH // Update caps from the hardware m_dwNumStreams = max(1, GetD3DCaps()->MaxStreams); m_dwMaxUserClipPlanes = GetD3DCaps()->MaxUserClipPlanes; // Update vertex processing state in the driver. We did not pass the // state when it was changed for performance reasons for (UINT i=0; i < sizeof(rsVertexProcessingList) / sizeof(D3DRENDERSTATETYPE); ++i) { D3DRENDERSTATETYPE dwState = (D3DRENDERSTATETYPE)rsVertexProcessingList[i]; if (CanHandleRenderState(dwState)) m_pDDI->SetRenderState(dwState, this->rstates[dwState]); } // Update clip planes for (i=0; i < m_dwMaxUserClipPlanes; i++) m_pDDI->SetClipPlane(i, (float*)&this->transform.userClipPlane[i]); // Update lights const UINT size = m_pLightArray->GetSize(); for (i = 0; i < size; i++) { DIRECT3DLIGHTI* pLight = static_cast ((*m_pLightArray)[i].m_pObj); if (pLight) { if (pLight->DirtyForDDI()) { m_pDDI->SetLight(i, &pLight->m_Light); pLight->ClearDirtyForDDI(); } } } // Update Enable/Disable light state. This is done separately to combine // multiple calls to the driver into one call. for (i = 0; i < size; i++) { DIRECT3DLIGHTI* pLight = static_cast ((*m_pLightArray)[i].m_pObj); if (pLight) { if (pLight->EnableDirtyForDDI()) { m_pDDI->LightEnable(i, pLight->Enabled()); pLight->ClearEnableDirtyForDDI(); } } } // Update transformation matrices if (this->pMatrixDirtyForDDI->IsBitSet(D3DTS_VIEW)) { m_pDDI->SetTransform(D3DTS_VIEW, &m_pv->view); this->pMatrixDirtyForDDI->ClearBit(D3DTS_VIEW); } if (this->pMatrixDirtyForDDI->IsBitSet(D3DTS_PROJECTION)) { m_pDDI->SetTransform(D3DTS_PROJECTION, &this->transform.proj); this->pMatrixDirtyForDDI->ClearBit(D3DTS_PROJECTION); } for (i=D3DTS_TEXTURE0; i <= D3DTS_TEXTURE7; i++) { if (this->pMatrixDirtyForDDI->IsBitSet(i)) { m_pDDI->SetTransform((D3DTRANSFORMSTATETYPE)i, &m_pv->mTexture[i - D3DTS_TEXTURE0]); this->pMatrixDirtyForDDI->ClearBit(i); } } for (i=0; i < __MAXWORLDMATRICES; i++) { UINT index = i + __WORLDMATRIXBASE; if (this->pMatrixDirtyForDDI->IsBitSet(index)) { m_pDDI->SetTransform((D3DTRANSFORMSTATETYPE)index, &m_pv->world[i]); this->pMatrixDirtyForDDI->ClearBit(index); } } // Update material m_pDDI->SetMaterial(&m_pv->lighting.material); m_MaxVertexShaderConst = GetD3DCaps()->MaxVertexShaderConst; // Update vertex shader constants if (m_dwRuntimeFlags & D3DRT_NEED_VSCONST_UPDATE) { VVM_WORD data[D3DVS_CONSTREG_MAX_V1_1]; UINT count = min(m_MaxVertexShaderConst, D3DVS_CONSTREG_MAX_V1_1); if (count) { m_pv->pGeometryFuncs->GetShaderConstants(0, count, &data); m_pDDI->SetVertexShaderConstant(0, &data, count); } m_dwRuntimeFlags &= ~D3DRT_NEED_VSCONST_UPDATE; } } PickDrawPrimFn(); } //--------------------------------------------------------------------- // This function is called from HALEXE.CPP, from device::SetRenderState and // from device::SetTexture. // #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::UpdateInternalState" void CD3DHal::UpdateInternalState(D3DRENDERSTATETYPE type, DWORD value) { switch (type) { #if DBG case D3DRS_DEBUGMONITORTOKEN: switch(value) { case D3DDMT_ENABLE: m_bDbgMonConnectionEnabled = TRUE; break; case D3DDMT_DISABLE: m_bDbgMonConnectionEnabled = FALSE; break; } rstates[type] = value; // update now so that rtdmon can access value. if( m_pDbgMon ) m_pDbgMon->NextEvent( D3DDM_EVENT_RSTOKEN ); break; #endif; //DBG case D3DRENDERSTATE_LIGHTING: if (value) m_pv->dwDeviceFlags |= D3DDEV_LIGHTING; else m_pv->dwDeviceFlags &= ~D3DDEV_LIGHTING; ForceFVFRecompute(); break; case D3DRENDERSTATE_FOGENABLE: rstates[type] = value; // set rstates BEFORE calling SetFogFlags SetFogFlags(); break; case D3DRENDERSTATE_SPECULARENABLE: this->dwFEFlags |= D3DFE_MATERIAL_DIRTY | D3DFE_LIGHTS_DIRTY | D3DFE_FRONTEND_DIRTY; if (value) m_pv->dwDeviceFlags |= D3DDEV_SPECULARENABLE; else m_pv->dwDeviceFlags &= ~D3DDEV_SPECULARENABLE; ForceFVFRecompute(); break; case D3DRENDERSTATE_AMBIENT: { const D3DVALUE SCALE = 1.0f/255.0f; m_pv->lighting.ambientSceneScaled.r = D3DVAL(RGBA_GETRED(value)); m_pv->lighting.ambientSceneScaled.g = D3DVAL(RGBA_GETGREEN(value)); m_pv->lighting.ambientSceneScaled.b = D3DVAL(RGBA_GETBLUE(value)); m_pv->lighting.ambientScene.r = m_pv->lighting.ambientSceneScaled.r * SCALE; m_pv->lighting.ambientScene.g = m_pv->lighting.ambientSceneScaled.g * SCALE; m_pv->lighting.ambientScene.b = m_pv->lighting.ambientSceneScaled.b * SCALE; m_pv->lighting.ambient_save = value; this->dwFEFlags |= D3DFE_MATERIAL_DIRTY | D3DFE_FRONTEND_DIRTY; break; } case D3DRENDERSTATE_RANGEFOGENABLE: if (value) m_pv->dwDeviceFlags |= D3DDEV_RANGEBASEDFOG; else m_pv->dwDeviceFlags &= ~D3DDEV_RANGEBASEDFOG; break; case D3DRENDERSTATE_FOGVERTEXMODE: m_pv->lighting.fog_mode = (D3DFOGMODE)value; SetFogFlags(); break; case D3DRENDERSTATE_COLORVERTEX: if (value) m_pv->dwDeviceFlags |= D3DDEV_COLORVERTEX; else m_pv->dwDeviceFlags &= ~D3DDEV_COLORVERTEX; // It is faster to initialize these values here, than setting a dirty // bit ang going through the slow UpdateState path m_pv->lighting.alpha = (DWORD)m_pv->lighting.materialAlpha; m_pv->lighting.alphaSpecular = (DWORD)m_pv->lighting.materialAlphaS; break; case D3DRENDERSTATE_CLIPPING: if (!value) { m_pv->dwDeviceFlags |= D3DDEV_DONOTCLIP; // Clear clip union and intersection flags m_pv->dwClipIntersection = 0; m_pv->dwClipUnion = 0; } else m_pv->dwDeviceFlags &= ~D3DDEV_DONOTCLIP; // Change our internal ProcessPrimitive functions which depend on // the clipping state m_pDDI->PickProcessPrimitive(); PickDrawPrimFn(); break; case D3DRENDERSTATE_FOGDENSITY: m_pv->lighting.fog_density = *(D3DVALUE*)&value; break; case D3DRENDERSTATE_FOGSTART: m_pv->lighting.fog_start = *(D3DVALUE*)&value; UpdateFogFactor(this->m_pv); break; case D3DRENDERSTATE_FOGEND: m_pv->lighting.fog_end = *(D3DVALUE*)&value; UpdateFogFactor(this->m_pv); break; case D3DRENDERSTATE_LOCALVIEWER: if (value) m_pv->dwDeviceFlags |= D3DDEV_LOCALVIEWER; else m_pv->dwDeviceFlags &= ~D3DDEV_LOCALVIEWER; this->dwFEFlags |= D3DFE_LIGHTS_DIRTY | D3DFE_FRONTEND_DIRTY; break; case D3DRENDERSTATE_NORMALIZENORMALS: if (value) { if (m_pv->dwDeviceFlags & D3DDEV_MODELSPACELIGHTING) { m_pv->dwDeviceFlags &= ~D3DDEV_MODELSPACELIGHTING; this->dwFEFlags |= D3DFE_NEED_TRANSFORM_LIGHTS | D3DFE_FRONTEND_DIRTY; } m_pv->dwDeviceFlags |= D3DDEV_NORMALIZENORMALS; } else { m_pv->dwDeviceFlags &= ~D3DDEV_NORMALIZENORMALS; if (!(m_pv->dwDeviceFlags & D3DDEV_MODELSPACELIGHTING)) this->dwFEFlags |= D3DFE_NEEDCHECKWORLDVIEWVMATRIX | D3DFE_FRONTEND_DIRTY; } break; case D3DRENDERSTATE_EMISSIVEMATERIALSOURCE: m_pv->lighting.dwEmissiveSrcIndex = 2; switch (value) { case D3DMCS_COLOR1: m_pv->lighting.dwEmissiveSrcIndex = 0; break; case D3DMCS_COLOR2: m_pv->lighting.dwEmissiveSrcIndex = 1; break; #if DBG case D3DMCS_MATERIAL: break; default: D3D_ERR("Illegal value for DIFFUSEMATERIALSOURCE"); goto error_exit; #endif } break; case D3DRENDERSTATE_DIFFUSEMATERIALSOURCE: m_pv->lighting.dwDiffuseSrcIndex = 2; switch (value) { case D3DMCS_COLOR1: m_pv->lighting.dwDiffuseSrcIndex = 0; break; case D3DMCS_COLOR2: m_pv->lighting.dwDiffuseSrcIndex = 1; break; #if DBG case D3DMCS_MATERIAL: break; default: D3D_ERR("Illegal value for DIFFUSEMATERIALSOURCE"); goto error_exit; #endif } break; case D3DRENDERSTATE_AMBIENTMATERIALSOURCE: m_pv->lighting.dwAmbientSrcIndex = 2; switch (value) { case D3DMCS_COLOR1: m_pv->lighting.dwAmbientSrcIndex = 0; break; case D3DMCS_COLOR2: m_pv->lighting.dwAmbientSrcIndex = 1; break; #if DBG case D3DMCS_MATERIAL: break; default: D3D_ERR("Illegal value for AMBIENTMATERIALSOURCE"); goto error_exit; #endif } break; case D3DRENDERSTATE_SPECULARMATERIALSOURCE: m_pv->lighting.dwSpecularSrcIndex = 2; switch (value) { case D3DMCS_COLOR1: m_pv->lighting.dwSpecularSrcIndex = 0; break; case D3DMCS_COLOR2: m_pv->lighting.dwSpecularSrcIndex = 1; break; #if DBG case D3DMCS_MATERIAL: break; default: D3D_ERR("Illegal value for SPECULARMATERIALSOURCE"); goto error_exit; #endif } break; case D3DRENDERSTATE_VERTEXBLEND: { #if DBG switch (value) { case D3DVBF_DISABLE: case D3DVBF_0WEIGHTS: case D3DVBF_1WEIGHTS: case D3DVBF_2WEIGHTS: case D3DVBF_3WEIGHTS: case D3DVBF_TWEENING: break; default: D3D_ERR("Illegal value for D3DRENDERSTATE_VERTEXBLEND"); goto error_exit; } #endif this->dwFEFlags |= D3DFE_VERTEXBLEND_DIRTY | D3DFE_FRONTEND_DIRTY; break; } case D3DRENDERSTATE_CLIPPLANEENABLE: { this->dwFEFlags |= D3DFE_CLIPPLANES_DIRTY | D3DFE_FRONTEND_DIRTY; m_pv->dwMaxUserClipPlanes = 0; break; } case D3DRENDERSTATE_SHADEMODE: if (value == D3DSHADE_FLAT) m_pv->dwDeviceFlags |= D3DDEV_FLATSHADEMODE; else m_pv->dwDeviceFlags &= ~D3DDEV_FLATSHADEMODE; break; case D3DRS_SOFTWAREVERTEXPROCESSING: // If DDI cannot do transformation and lighting, // D3DRT_RSSOFTWAREPROCESSING is always set to TRUE if( BehaviorFlags() & D3DCREATE_MIXED_VERTEXPROCESSING ) { DDASSERT( m_pDDI->CanDoTL() ); if (value != this->rstates[type]) SwitchVertexProcessingMode(value); } break; case D3DRS_POINTSCALEENABLE: if (value) { // We need world-view matrix to scale point sprites this->dwFEFlags |= D3DFE_WORLDVIEWMATRIX_DIRTY | D3DFE_FRONTEND_DIRTY; } break; case D3DRS_POINTSIZE: if (*(float*)&value != 1.0f) m_dwRuntimeFlags |= D3DRT_POINTSIZEINRS; else m_dwRuntimeFlags &= ~D3DRT_POINTSIZEINRS; break; case D3DRS_POINTSIZE_MAX: { float MaxPointSize = GetD3DCaps()->MaxPointSize; if (MaxPointSize == 0) MaxPointSize = __MAX_POINT_SIZE; if (*(float*)&value <= MaxPointSize) m_pv->PointSizeMax = *(float*)&value; #if DBG else { D3D_ERR("Max point size is greater than supported by the device"); goto error_exit; } #endif } break; case D3DRS_INDEXEDVERTEXBLENDENABLE: if (value) m_pv->dwDeviceFlags |= D3DDEV_INDEXEDVERTEXBLENDENABLE; else m_pv->dwDeviceFlags &= ~D3DDEV_INDEXEDVERTEXBLENDENABLE; ForceFVFRecompute(); break; case D3DRS_PATCHSEGMENTS: { const D3DCAPS8* pCaps = GetD3DCaps(); if (!(pCaps->DevCaps & D3DDEVCAPS_NPATCHES) && (pCaps->DevCaps & D3DDEVCAPS_RTPATCHES)) { if (*(float*)&value > 1.0f) m_dwRuntimeFlags |= D3DRT_DONPATCHCONVERSION; else m_dwRuntimeFlags &= ~D3DRT_DONPATCHCONVERSION; rstates[type] = value; // Must set before Pick PickDrawPrimFn(); } } break; default: // WRAP render states could be re-mapped so we have to restore them before // setting a new value if (type >= D3DRENDERSTATE_WRAP0 && type <= D3DRENDERSTATE_WRAP7) { if (m_pv->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { RestoreTextureStages(this); ForceFVFRecompute(); } } break; } rstates[type] = value; // set rstates for all other cases return; #if DBG error_exit: throw D3DERR_INVALIDCALL; #endif } //--------------------------------------------------------------------- #if DBG static char ProfileStr[PROF_DRAWINDEXEDPRIMITIVEVB+1][32]= { "Execute", "Begin", "BeginIndexed", "DrawPrimitive(Device2)", "DrawIndexedPrimitive(Device2)", "DrawPrimitiveStrided", "DrawIndexedPrimitiveStrided", "DrawPrimitive(Device7)", "DrawIndexedPrimitive(Device7)", "DrawPrimitiveVB", "DrawIndexedPrimitiveVB", }; static char PrimitiveStr[D3DPT_TRIANGLEFAN][16]= { "POINTLIST", "LINELIST", "LINESTRIP", "TRIANGLELIST", "TRIANGLESTRIP", "TRIANGLEFAN", }; static char VertexStr[D3DVT_TLVERTEX][16]= { "D3DVERTEX", "D3DLVERTEX", "D3DTLVERTEX", }; #define PROFILE_LEVEL 0 void CD3DHal::Profile(DWORD caller, D3DPRIMITIVETYPE dwPrimitive, DWORD dwVertex) { DWORD bitwisecaller= 1 << caller; DWORD bitwisePrimitive = 1 << (DWORD)dwPrimitive; DWORD bitwiseVertex1 = 1 << (dwVertex & 0x001F); DWORD bitwiseVertex2 = 1 << ((dwVertex & 0x03E0) >> 5); char str[256]; DDASSERT(PROF_DRAWINDEXEDPRIMITIVEVB >= caller); DDASSERT(D3DPT_TRIANGLEFAN >= dwPrimitive && D3DPT_POINTLIST<= dwPrimitive); if (dwCaller & bitwisecaller) { if (dwPrimitiveType[caller] & bitwisePrimitive) { if ((dwVertexType1[caller] & bitwiseVertex1) && (dwVertexType2[caller] & bitwiseVertex2)) { return; //matching a previous api call, no spew, could count stat though } else { dwVertexType1[caller] |= bitwiseVertex1; dwVertexType2[caller] |= bitwiseVertex2; } } else { dwPrimitiveType[caller] |= bitwisePrimitive; dwVertexType1[caller] |= bitwiseVertex1; dwVertexType2[caller] |= bitwiseVertex2; } } else { this->dwCaller |= bitwisecaller; dwPrimitiveType[caller] |= bitwisePrimitive; dwVertexType1[caller] |= bitwiseVertex1; dwVertexType2[caller] |= bitwiseVertex2; } wsprintf( (LPSTR) str, ProfileStr[caller]); strcat(str,":"); strcat(str,PrimitiveStr[dwPrimitive-1]); if (dwVertex > D3DVT_TLVERTEX) { if (dwVertex == D3DFVF_VERTEX) { dwVertex = D3DVT_VERTEX; } else if (dwVertex == D3DFVF_TLVERTEX) { dwVertex = D3DVT_TLVERTEX; } else { D3D_INFO(PROFILE_LEVEL,"Profile:%s FVFType=%08lx",str,dwVertex); return; } } else { DDASSERT(dwVertex >= D3DVT_VERTEX); } strcat(str,":"); strcat(str,VertexStr[dwVertex-1]); D3D_INFO(PROFILE_LEVEL,"Profile:%s",str); } #endif // DBG //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::MultiplyTransformI" // MultiplyTransform -- this preconcatenates the new matrix to the specified // transform matrix // // this really screams for overloaded matrix ops... // void CD3DHal::MultiplyTransformI(D3DTRANSFORMSTATETYPE state, CONST D3DMATRIX* lpMat) { D3DMATRIXI mResult; if ((DWORD)state >= __WORLDMATRIXBASE && (DWORD)state < (__WORLDMATRIXBASE + __MAXWORLDMATRICES)) { // World matrix is set UINT index = (DWORD)state - __WORLDMATRIXBASE; MatrixProduct(&mResult, (D3DMATRIXI*)lpMat, &m_pv->world[index]); m_pv->world[index] = mResult; if (index == 0) this->dwFEFlags |= D3DFE_WORLDMATRIX_DIRTY | D3DFE_FRONTEND_DIRTY; } else switch (state) { case D3DTS_VIEW : MatrixProduct(&mResult, (D3DMATRIXI*)lpMat, &m_pv->view); m_pv->view = mResult; this->dwFEFlags |= D3DFE_VIEWMATRIX_DIRTY | D3DFE_FRONTEND_DIRTY; break; case D3DTS_PROJECTION : MatrixProduct(&mResult, (D3DMATRIXI*)lpMat, &this->transform.proj); this->transform.proj = mResult; this->dwFEFlags |= D3DFE_PROJMATRIX_DIRTY | D3DFE_FRONTEND_DIRTY; break; case D3DTS_TEXTURE0: case D3DTS_TEXTURE1: case D3DTS_TEXTURE2: case D3DTS_TEXTURE3: case D3DTS_TEXTURE4: case D3DTS_TEXTURE5: case D3DTS_TEXTURE6: case D3DTS_TEXTURE7: { DWORD dwIndex = state - D3DTS_TEXTURE0; MatrixProduct(&mResult, (D3DMATRIXI*)lpMat, &m_pv->mTexture[dwIndex]); m_pv->mTexture[dwIndex] = mResult; break; } default : D3D_THROW_FAIL("Invalid state value passed to MultiplyTransform"); } m_pv->MatrixStateCount++; if (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING) this->pMatrixDirtyForDDI->SetBit(state); else m_pDDI->SetTransform(state, (LPD3DMATRIX)&mResult); // W range should always be updated if (state == D3DTS_PROJECTION) m_pDDI->UpdateWInfo((LPD3DMATRIX)&mResult); } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DBase::BeginStateBlock" HRESULT D3DAPI CD3DBase::BeginStateBlock() { API_ENTER(this); // Takes D3D Lock if necessary try { if (this->m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE) { D3D_ERR("Already in the state record mode. BeginStateBlock failed."); return D3DERR_INVALIDCALL; } if (m_pStateSets->StartNewSet() != D3D_OK) { D3D_ERR("Could not allocate memory for new state block. BeginStateBlock failed."); return E_OUTOFMEMORY; } this->m_dwRuntimeFlags |= D3DRT_RECORDSTATEMODE; #ifdef FAST_PATH FastPathSetRenderStateRecord(); FastPathSetTextureStageStateRecord(); FastPathApplyStateBlockRecord(); FastPathSetTextureRecord(); FastPathSetVertexShaderSlow(); FastPathSetStreamSourceSlow(); FastPathSetIndicesSlow(); FastPathSetMaterialRecord(); FastPathMultiplyTransformRecord(); FastPathSetTransformRecord(); FastPathSetPixelShaderRecord(); FastPathSetPixelShaderConstantRecord(); FastPathSetVertexShaderConstantRecord(); #endif // FAST_PATH return D3D_OK; } catch (HRESULT ret) { D3D_ERR("BeginStateBlock failed."); return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DBase::EndStateBlock" HRESULT D3DAPI CD3DBase::EndStateBlock(LPDWORD pdwHandle) { API_ENTER(this); // Takes D3D Lock if necessary if (!VALID_WRITEPTR(pdwHandle, sizeof(DWORD))) { D3D_ERR( "Invalid DWORD pointer. EndStateBlock failed." ); return D3DERR_INVALIDCALL; } try { if (!(this->m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE)) { D3D_ERR("Not in state record mode. EndStateBlock failed."); return D3DERR_INVALIDCALL; } this->m_dwRuntimeFlags &= ~D3DRT_RECORDSTATEMODE; m_pStateSets->EndSet(); #ifdef FAST_PATH FastPathSetRenderStateExecute(); FastPathSetTextureStageStateExecute(); FastPathSetMaterialExecute(); FastPathSetVertexShaderFast(); FastPathSetStreamSourceFast(); FastPathSetIndicesFast(); FastPathApplyStateBlockExecute(); FastPathSetTextureExecute(); FastPathSetTransformExecute(); FastPathMultiplyTransformExecute(); FastPathSetPixelShaderExecute(); FastPathSetPixelShaderConstantExecute(); FastPathSetVertexShaderConstantExecute(); #endif // FAST_PATH this->m_pDDI->WriteStateSetToDevice((D3DSTATEBLOCKTYPE)0); *pdwHandle = m_pStateSets->GetCurrentHandle(); return D3D_OK; } catch(HRESULT ret) { D3D_ERR("EndStateBlock failed."); m_pStateSets->Cleanup(m_pStateSets->GetCurrentHandle()); *pdwHandle = 0xFFFFFFFF; return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DBase::DeleteStateBlock" HRESULT D3DAPI CD3DBase::DeleteStateBlock(DWORD dwHandle) { API_ENTER(this); // Takes D3D Lock if necessary try { if (this->m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE) { D3D_ERR("We are in state record mode. DeleteStateBlock failed."); return D3DERR_INVALIDCALL; } m_pStateSets->DeleteStateSet(this, dwHandle); return D3D_OK; } catch(HRESULT ret) { D3D_ERR("DeleteStateBlock failed."); return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DBase::ApplyStateBlock" HRESULT D3DAPI CD3DBase::ApplyStateBlock(DWORD dwHandle) { API_ENTER(this); // Takes D3D Lock if necessary try { if (this->m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE) { D3D_ERR("We are in state record mode. ApplyStateBlock failed."); return D3DERR_INVALIDCALL; } return ApplyStateBlockFast(dwHandle); } catch(HRESULT ret) { D3D_ERR("ApplyStateBlock failed."); return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DBase::ApplyStateBlockFast" HRESULT D3DAPI CD3DBase::ApplyStateBlockFast(DWORD dwHandle) { // NOTE: This can become a public API through the // v-table hack. This should only happen for // single-threaded apps; so we don't need // to take the critical section. // API_ENTER(this); // Takes D3D Lock if necessary try { m_pStateSets->Execute(this, dwHandle); return D3D_OK; } catch(HRESULT ret) { D3D_ERR("ApplyStateBlock failed."); return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DBase::CaptureStateBlock" HRESULT D3DAPI CD3DBase::CaptureStateBlock(DWORD dwHandle) { API_ENTER(this); // Takes D3D Lock if necessary try { if (this->m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE) { D3D_ERR("Cannot capture when in the state record mode. CaptureStateBlock failed."); return D3DERR_INVALIDCALL; } m_pStateSets->Capture(this, dwHandle); return D3D_OK; } catch (HRESULT ret) { D3D_ERR("CaptureStateBlock failed."); return ret; } } //--------------------------------------------------------------------- // Input: // type - FVF control dword // // Returns D3D_OK, if the control dword is valid. // D3DERR_INVALIDCALL otherwise // #undef DPF_MODNAME #define DPF_MODNAME "CD3DBase::ValidateFVF" HRESULT __declspec(nothrow) CD3DBase::ValidateFVF(DWORD type) { DWORD dwTexCoord = FVF_TEXCOORD_NUMBER(type); DWORD vertexType = type & D3DFVF_POSITION_MASK; // Texture format bits above texture count should be zero // Reserved field 0 and 2 should be 0 // Reserved 1 should be set only for LVERTEX // Only two vertex position types allowed if (type & g_TextureFormatMask[dwTexCoord]) { D3D_ERR("FVF Validation error: FVF has incorrect texture format"); goto error; } if (type & 0xFFFF0000 && vertexType == D3DFVF_XYZRHW && m_dwRuntimeFlags & D3DRT_ONLY2FLOATSPERTEXTURE) { D3D_ERR("FVF Validation error: The D3D device supports only two floats per texture coordinate set"); goto error; } if (type & D3DFVF_RESERVED0) { D3D_ERR("FVF has reserved bit(s) set"); goto error; } if (!(vertexType == D3DFVF_XYZRHW || vertexType == D3DFVF_XYZ || vertexType == D3DFVF_XYZB1 || vertexType == D3DFVF_XYZB2 || vertexType == D3DFVF_XYZB3 || vertexType == D3DFVF_XYZB4 || vertexType == D3DFVF_XYZB5)) { D3D_ERR("FVF Validation error: FVF has incorrect position type"); goto error; } if (vertexType == D3DFVF_XYZRHW && type & D3DFVF_NORMAL) { D3D_ERR("FVF Validation error: Normal should not be used with XYZRHW position type"); goto error; } return D3D_OK; error: return D3DERR_INVALIDCALL; } //--------------------------------------------------------------------- // Returns TRUE, if driver state should not be updated // #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::UpdateInternalTextureStageState" BOOL CD3DHal::UpdateInternalTextureStageState (DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, DWORD* pValue) { DWORD dwValue = *pValue; BOOL ret = FALSE; // return TRUE if TSS should NOT be batched if(dwState == D3DTSS_COLOROP) { if(dwValue == D3DTOP_DISABLE || tsstates[dwStage][D3DTSS_COLOROP] == D3DTOP_DISABLE) ForceFVFRecompute(); } else if (dwState == D3DTSS_TEXCOORDINDEX) { if (TextureTransformEnabled(this)) { ForceFVFRecompute(); } DWORD dwTexGenMode = 0; if (dwValue >= D3DDP_MAXTEXCOORD) { dwTexGenMode = dwValue & ~0xFFFF; if(!m_pDDI->CanDoTL()) ret = TRUE; #if DBG DWORD dwTexIndex = dwValue & 0xFFFF; if (!(dwTexGenMode == D3DTSS_TCI_CAMERASPACENORMAL || dwTexGenMode == D3DTSS_TCI_CAMERASPACEPOSITION || dwTexGenMode == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR) || dwTexIndex > D3DDP_MAXTEXCOORD) { D3D_ERR("Incorrect texture coordinate set index"); throw D3DERR_INVALIDCALL; } #endif } // Now we need to update internal flag (dwFlags2) which says whether // texture generation for the stage is enabled DWORD dwTexGenBit = __FLAGS2_TEXGEN0 << dwStage; if (dwTexGenMode == D3DTSS_TCI_CAMERASPACENORMAL || dwTexGenMode == D3DTSS_TCI_CAMERASPACEPOSITION || dwTexGenMode == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR) { // We need to update internal flags when tex gen mode is changed, // so always call ForceFVFRecompute ForceFVFRecompute(); m_pv->dwFlags2 |= dwTexGenBit; } else { // As optimization, recompute FVF only if texture generation for // the stage was enabled if (m_pv->dwFlags2 & dwTexGenBit) { ForceFVFRecompute(); m_pv->dwFlags2 &= ~dwTexGenBit; } } } else if (dwState == D3DTSS_TEXTURETRANSFORMFLAGS) { DWORD dwEnableBit = 1 << dwStage; // To check internal "enable" dword // Force to re-compute FVF only if enable state is changed if ((dwValue & ~D3DTTFF_PROJECTED) == D3DTTFF_DISABLE) { if (m_pv->dwFlags2 & dwEnableBit) { ForceFVFRecompute(); m_pv->dwFlags2 &= ~dwEnableBit; } } else { if (!(m_pv->dwFlags2 & dwEnableBit)) { ForceFVFRecompute(); m_pv->dwFlags2 |= dwEnableBit; } } // Do not pass texture transform flags to DX6 devices if(GetDDIType() == D3DDDITYPE_DX6) ret = TRUE; // When we need to emulate projected textures we do not pass "projected" // bit to the device. We also decrease the float count. if (m_dwRuntimeFlags & D3DRT_EMULATEPROJECTEDTEXTURE) { // Compute projected bit DWORD dwEnableBit = __FLAGS2_TEXPROJ0 << dwStage; if (dwValue & D3DTTFF_PROJECTED) { // Remove projected bit. Note that tsstates will keep the // original value *pValue &= ~D3DTTFF_PROJECTED; // Reduce float count if (*pValue != D3DTTFF_DISABLE) (*pValue)--; if (!(m_pv->dwFlags2 & dwEnableBit)) { ForceFVFRecompute(); m_pv->dwFlags2 |= dwEnableBit; } } else { // Just clear projection enabled bit and recompute FVF if (m_pv->dwFlags2 & dwEnableBit) { ForceFVFRecompute(); m_pv->dwFlags2 &= ~dwEnableBit; } } } } else if(dwState > D3DTSS_TEXTURETRANSFORMFLAGS) { if(GetDDIType() == D3DDDITYPE_DX6) ret = TRUE; } // Update runtime copy of state. tsstates[dwStage][dwState] = dwValue; return ret; } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::SetClipPlaneI" void CD3DHal::SetClipPlaneI(DWORD dwPlaneIndex, CONST D3DVALUE* pPlaneEquation) { D3DVALUE *p = &this->transform.userClipPlane[dwPlaneIndex].x; p[0] = pPlaneEquation[0]; p[1] = pPlaneEquation[1]; p[2] = pPlaneEquation[2]; p[3] = pPlaneEquation[3]; this->dwFEFlags |= D3DFE_CLIPPLANES_DIRTY | D3DFE_FRONTEND_DIRTY; if (!(m_dwRuntimeFlags & (D3DRT_EXECUTESTATEMODE | D3DRT_RSSOFTWAREPROCESSING))) { m_pDDI->SetClipPlane(dwPlaneIndex, pPlaneEquation); } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::GetClipPlane" HRESULT D3DAPI CD3DHal::GetClipPlane(DWORD dwPlaneIndex, D3DVALUE* pPlaneEquation) { API_ENTER(this); // Takes D3D Lock if necessary #if DBG if (dwPlaneIndex >= __MAXUSERCLIPPLANES) { D3D_ERR("Plane index is too big. GetClipPlane failed."); return D3DERR_INVALIDCALL; } if (!VALID_WRITEPTR(pPlaneEquation, sizeof(D3DVALUE)*4)) { D3D_ERR( "Invalid plane pointer. GetClipPlane failed." ); return D3DERR_INVALIDCALL; } #endif try { D3DVALUE *p = &this->transform.userClipPlane[dwPlaneIndex].x; pPlaneEquation[0] = p[0]; pPlaneEquation[1] = p[1]; pPlaneEquation[2] = p[2]; pPlaneEquation[3] = p[3]; } catch(HRESULT ret) { D3D_ERR("GetClipPlane failed."); return ret; } return D3D_OK; } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DBase::CreateStateBlock" HRESULT D3DAPI CD3DBase::CreateStateBlock(D3DSTATEBLOCKTYPE sbt, LPDWORD pdwHandle) { API_ENTER(this); // Takes D3D Lock if necessary if (!VALID_WRITEPTR(pdwHandle, sizeof(DWORD))) { D3D_ERR( "Invalid DWORD pointer. CreateStateBlock failed." ); return D3DERR_INVALIDCALL; } try { if (this->m_dwRuntimeFlags & D3DRT_RECORDSTATEMODE) { D3D_ERR("Cannot create state block when in the state record mode. CreateStateBlock failed."); return D3DERR_INVALIDCALL; } m_pStateSets->CreatePredefined(this, sbt); *pdwHandle = m_pStateSets->GetCurrentHandle(); } catch (HRESULT ret) { D3D_ERR("CreateStateBlock failed."); m_pStateSets->Cleanup(m_pStateSets->GetCurrentHandle()); *pdwHandle = 0xFFFFFFFF; return ret; } return D3D_OK; } //--------------------------------------------------------------------- // Restore indices in the texture stages which were re-mapped for texture // transforms // We have to do restore if // - Set or Get render state is issued with _WRAP parameter // - Set or Get texture stage is issued with TEXCOORDINDEX as a parameter // void RestoreTextureStages(LPD3DHAL pDevI) { D3DFE_PROCESSVERTICES* pv = pDevI->m_pv; // dwVIDIn is used to force re-compute FVF in the // SetTextureStageState. so we save and restore it. DWORD dwVIDInSaved = pv->dwVIDIn; pv->dwDeviceFlags &= ~D3DDEV_REMAPTEXTUREINDICES; for (DWORD i=0; i < pDevI->dwNumTextureStagesToRemap; i++) { LPD3DFE_TEXTURESTAGE pStage = &pDevI->textureStageToRemap[i]; // Texture generation mode was stripped out of pStage->dwInpCoordIndex DWORD dwInpIndex = pStage->dwInpCoordIndex + pStage->dwTexGenMode; if (dwInpIndex != pStage->dwOutCoordIndex) { // We do not call UpdateInternalTextureStageState because it // will call ForceRecomputeFVF and we do not want this. pDevI->tsstates[pStage->dwOrgStage][D3DTSS_TEXCOORDINDEX] = dwInpIndex; // Filter texgen modes for non-TL drivers if (pDevI->m_pDDI->CanDoTL() || dwInpIndex < D3DDP_MAXTEXCOORD) { pDevI->m_pDDI->SetTSS(pStage->dwOrgStage, D3DTSS_TEXCOORDINDEX, dwInpIndex); } } DWORD dwState = D3DRENDERSTATE_WRAP0 + pStage->dwOutCoordIndex; if (pStage->dwOrgWrapMode != pDevI->rstates[dwState]) { // We do not call UpdateInternaState because it // will call ForceRecomputeFVF and we do not want this. pDevI->rstates[dwState] = pStage->dwOrgWrapMode; pDevI->m_pDDI->SetRenderState((D3DRENDERSTATETYPE)dwState, pStage->dwOrgWrapMode); } } pv->dwVIDIn = dwVIDInSaved; }