/*==========================================================================; * * Copyright (C) 1998 Microsoft Corporation. All Rights Reserved. * * File: d3ddev.cpp * Content: Direct3D device implementation *@@BEGIN_MSINTERNAL * * $Id: device.c,v 1.26 1995/12/04 11:29:47 sjl Exp $ * *@@END_MSINTERNAL * ***************************************************************************/ #include "pch.cpp" #pragma hdrstop /* * Create an api for the Direct3DDevice object */ extern "C" { #define this _this #include "ddrawpr.h" #undef this } #include "drawprim.hpp" #include "fe.h" #include "enum.hpp" //#define APIPROF #ifdef APIPROF #include "apiprof.cpp" #endif //APIPROF #if defined(PROFILE4) #include #elif defined(PROFILE) #include #endif // Remove DDraw's type unsafe definition and replace with our C++ friendly def #ifdef VALIDEX_CODE_PTR #undef VALIDEX_CODE_PTR #endif #define VALIDEX_CODE_PTR( ptr ) \ (!IsBadCodePtr( (FARPROC) ptr ) ) #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice" extern void setIdentity(D3DMATRIXI * m); #ifndef PROFILE4 #ifdef _X86_ extern HRESULT D3DAPI katmai_FEContextCreate(DWORD dwFlags, LPD3DFE_PVFUNCS *lpLeafFuncs); extern HRESULT D3DAPI wlmt_FEContextCreate(DWORD dwFlags, LPD3DFE_PVFUNCS *lpLeafFuncs); extern HRESULT D3DAPI x3DContextCreate(DWORD dwFlags, LPD3DFE_PVFUNCS *lpLeafFuncs); #endif #endif #ifdef _X86_ extern BOOL IsWin95(); #endif extern HINSTANCE hMsGeometryDLL; // This is a list of all rstates that UpdateInternalState does some // work other than updating this->rstates[] array. This is used to // do a quick bitwise check to see if this rstate is trivial or not. const D3DRENDERSTATETYPE rsList[] = { // renderstates that either need runtime attention or that cannot be sent // to legacy drivers D3DRENDERSTATE_FOGENABLE, D3DRENDERSTATE_SPECULARENABLE, D3DRENDERSTATE_RANGEFOGENABLE, D3DRENDERSTATE_FOGDENSITY, D3DRENDERSTATE_FOGSTART, D3DRENDERSTATE_FOGEND, D3DRENDERSTATE_WRAP0, D3DRENDERSTATE_WRAP1, D3DRENDERSTATE_WRAP2, D3DRENDERSTATE_WRAP3, D3DRENDERSTATE_WRAP4, D3DRENDERSTATE_WRAP5, D3DRENDERSTATE_WRAP6, D3DRENDERSTATE_WRAP7, D3DRENDERSTATE_CLIPPING, D3DRENDERSTATE_LIGHTING, D3DRENDERSTATE_AMBIENT, D3DRENDERSTATE_FOGVERTEXMODE, D3DRENDERSTATE_COLORVERTEX, D3DRENDERSTATE_LOCALVIEWER, D3DRENDERSTATE_NORMALIZENORMALS, D3DRENDERSTATE_COLORKEYBLENDENABLE, D3DRENDERSTATE_DIFFUSEMATERIALSOURCE, D3DRENDERSTATE_SPECULARMATERIALSOURCE, D3DRENDERSTATE_AMBIENTMATERIALSOURCE, D3DRENDERSTATE_EMISSIVEMATERIALSOURCE, D3DRENDERSTATE_VERTEXBLEND, D3DRENDERSTATE_CLIPPLANEENABLE, D3DRENDERSTATE_SHADEMODE, D3DRS_SOFTWAREVERTEXPROCESSING, D3DRS_POINTSIZE, D3DRS_POINTSIZE_MIN, D3DRS_POINTSPRITEENABLE, D3DRS_POINTSCALEENABLE, D3DRS_POINTSCALE_A, D3DRS_POINTSCALE_B, D3DRS_POINTSCALE_C, D3DRS_MULTISAMPLEANTIALIAS, D3DRS_MULTISAMPLEMASK, D3DRS_PATCHEDGESTYLE, D3DRS_PATCHSEGMENTS, D3DRS_DEBUGMONITORTOKEN, D3DRS_POINTSIZE_MAX, D3DRS_INDEXEDVERTEXBLENDENABLE, D3DRS_COLORWRITEENABLE, D3DRS_TWEENFACTOR, D3DRS_DEBUGMONITORTOKEN, D3DRS_BLENDOP, D3DRS_PATCHSEGMENTS, // Retired renderstates to be filtered with DPF error and INVALID return // NOTE: everything listed here is also assumed to appear in rsListRetired D3DRENDERSTATE_TEXTUREHANDLE, D3DRENDERSTATE_TEXTUREADDRESS, D3DRENDERSTATE_WRAPU, D3DRENDERSTATE_WRAPV, D3DRENDERSTATE_MONOENABLE, D3DRENDERSTATE_ROP2, D3DRENDERSTATE_PLANEMASK, D3DRENDERSTATE_TEXTUREMAG, D3DRENDERSTATE_TEXTUREMIN, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DRENDERSTATE_SUBPIXEL, D3DRENDERSTATE_SUBPIXELX, D3DRENDERSTATE_STIPPLEENABLE, D3DRENDERSTATE_BORDERCOLOR, D3DRENDERSTATE_TEXTUREADDRESSU, D3DRENDERSTATE_TEXTUREADDRESSV, D3DRENDERSTATE_MIPMAPLODBIAS, D3DRENDERSTATE_ANISOTROPY, D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT, 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, // newly retired for DX8 D3DRENDERSTATE_ANTIALIAS, D3DRENDERSTATE_TEXTUREPERSPECTIVE, D3DRENDERSTATE_COLORKEYENABLE, D3DRENDERSTATE_COLORKEYBLENDENABLE, D3DRENDERSTATE_STIPPLEDALPHA, }; // list of retired renderstates - need to make sure these are // filtered and never get from app directly to driver const D3DRENDERSTATETYPE rsListRetired[] = { D3DRENDERSTATE_TEXTUREHANDLE, D3DRENDERSTATE_TEXTUREADDRESS, D3DRENDERSTATE_WRAPU, D3DRENDERSTATE_WRAPV, D3DRENDERSTATE_MONOENABLE, D3DRENDERSTATE_ROP2, D3DRENDERSTATE_PLANEMASK, D3DRENDERSTATE_TEXTUREMAG, D3DRENDERSTATE_TEXTUREMIN, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DRENDERSTATE_SUBPIXEL, D3DRENDERSTATE_SUBPIXELX, D3DRENDERSTATE_STIPPLEENABLE, D3DRENDERSTATE_BORDERCOLOR, D3DRENDERSTATE_TEXTUREADDRESSU, D3DRENDERSTATE_TEXTUREADDRESSV, D3DRENDERSTATE_MIPMAPLODBIAS, D3DRENDERSTATE_ANISOTROPY, D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT, 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, // newly retired for DX8 D3DRENDERSTATE_ANTIALIAS, D3DRENDERSTATE_TEXTUREPERSPECTIVE, D3DRENDERSTATE_COLORKEYENABLE, D3DRENDERSTATE_COLORKEYBLENDENABLE, D3DRENDERSTATE_STIPPLEDALPHA, }; ///////////////////////////////////////////////////////////////////////////// // // // CD3DHal // // // ///////////////////////////////////////////////////////////////////////////// //--------------------------------------------------------------------- CD3DHal::CD3DHal() { //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // DO NOT PUT INITIALIZATION IN THE CONSTRUCTOR. // Put it in Init() instead. This is because the device can be // "Destroy()ed" and "Init()ed" anytime via Reset. In this // situation, the constructor is never called. (snene 01/00) //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::StateInitialize" void CD3DHal::StateInitialize(BOOL bZEnable) { DWORD i,j; // Initialize the bit array indicating the rstates needing non-trivial // work. for (i=0; i < sizeof(rsList) / sizeof(D3DRENDERSTATETYPE); ++i) rsVec.SetBit(rsList[i]); // Initialize the bit array indicating the retired rstates for (i=0; i < sizeof(rsListRetired) / sizeof(D3DRENDERSTATETYPE); ++i) rsVecRetired.SetBit(rsListRetired[i]); // Initialize the bit array indicating the vertex processing only rstates for (i=0; i < sizeof(rsVertexProcessingList) / sizeof(D3DRENDERSTATETYPE); ++i) rsVertexProcessingOnly.SetBit(rsVertexProcessingList[i]); // Obviate Set(Render;TextureStage)State filtering 'redundant' device state settings // since this is the init step. // memset( this->rstates, 0xff, sizeof(DWORD)*D3D_MAXRENDERSTATES); for (i=0; irstates[i] = 0xbaadcafe; // memset( this->tsstates, 0xff, sizeof(DWORD)*D3DHAL_TSS_MAXSTAGES*D3DHAL_TSS_STATESPERSTAGE ); for (j=0; jtsstates[j][i] = 0xbaadcafe; CD3DBase::StateInitialize(bZEnable); if (GetDDIType() < D3DDDITYPE_DX8) { SetRenderStateInternal(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE); SetRenderStateInternal(D3DRENDERSTATE_COLORKEYENABLE, FALSE); SetRenderStateInternal(D3DRENDERSTATE_COLORKEYBLENDENABLE, FALSE); SetRenderStateInternal(D3DRENDERSTATE_STIPPLEDALPHA, FALSE); } if (GetDDIType() < D3DDDITYPE_DX7) { // send retired renderstate init's to pre-DX7 HALs only SetRenderStateInternal( D3DRENDERSTATE_STIPPLEENABLE, FALSE); SetRenderStateInternal( D3DRENDERSTATE_MONOENABLE, FALSE); SetRenderStateInternal( D3DRENDERSTATE_ROP2, R2_COPYPEN); SetRenderStateInternal( D3DRENDERSTATE_PLANEMASK, (DWORD)~0); SetRenderStateInternal( D3DRENDERSTATE_WRAPU, FALSE); SetRenderStateInternal( D3DRENDERSTATE_WRAPV, FALSE); SetRenderStateInternal( D3DRENDERSTATE_ANTIALIAS, FALSE); SetRenderStateInternal( D3DRENDERSTATE_SUBPIXEL, FALSE); /* 30 */ SetRenderStateInternal( D3DRENDERSTATE_SUBPIXELX, FALSE); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN00, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN01, 0); /* 40 */ SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN02, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN03, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN04, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN05, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN06, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN07, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN08, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN09, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN10, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN11, 0); /* 50 */ SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN12, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN13, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN14, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN15, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN16, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN17, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN18, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN19, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN20, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN21, 0); /* 60 */ SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN22, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN23, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN24, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN25, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN26, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN27, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN28, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN29, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN30, 0); SetRenderStateInternal( D3DRENDERSTATE_STIPPLEPATTERN31, 0); /* 70 */ } if( BehaviorFlags() & D3DCREATE_SOFTWARE_VERTEXPROCESSING ) { SwitchVertexProcessingMode(TRUE); rstates[D3DRS_SOFTWAREVERTEXPROCESSING] = TRUE; } else if( BehaviorFlags() & D3DCREATE_HARDWARE_VERTEXPROCESSING ) { SwitchVertexProcessingMode(FALSE); rstates[D3DRS_SOFTWAREVERTEXPROCESSING] = FALSE; } else if( BehaviorFlags() & D3DCREATE_MIXED_VERTEXPROCESSING ) { SetRenderStateInternal( D3DRS_SOFTWAREVERTEXPROCESSING, 0); } else { D3D_INFO( 0, "No Vertex Processing behavior specified, assuming software" ); SwitchVertexProcessingMode(TRUE); rstates[D3DRS_SOFTWAREVERTEXPROCESSING] = TRUE; } } /* * Initialisation - class part and device part */ //--------------------------------------------------------------------- HRESULT CD3DHal::D3DFE_Create() { DDSURFACEDESC ddsd; HRESULT hr; const D3DCAPS8 *pCaps = GetD3DCaps(); if (m_pDDI->GetDDIType() < D3DDDITYPE_DX7) { m_dwRuntimeFlags |= D3DRT_ONLY2FLOATSPERTEXTURE; } else if (m_pDDI->GetDDIType() < D3DDDITYPE_DX8) { // Some drivers (G200, G400) cannot handle more than 2 floats in // texture coordinates, even they are supposed to. We set the // runtime bit to mark such drivers and compute output FVF for vertex // shaders accordingly if (!(pCaps->TextureCaps & D3DPTEXTURECAPS_PROJECTED || pCaps->TextureCaps & D3DPTEXTURECAPS_CUBEMAP)) { m_dwRuntimeFlags |= D3DRT_ONLY2FLOATSPERTEXTURE; } } if (!(pCaps->TextureCaps & D3DPTEXTURECAPS_PROJECTED)) m_dwRuntimeFlags |= D3DRT_EMULATEPROJECTEDTEXTURE; if (pCaps && pCaps->FVFCaps) { this->m_pv->dwMaxTextureIndices = pCaps->FVFCaps & D3DFVFCAPS_TEXCOORDCOUNTMASK; if (pCaps->FVFCaps & D3DFVFCAPS_DONOTSTRIPELEMENTS) this->m_pv->dwDeviceFlags |= D3DDEV_DONOTSTRIPELEMENTS; DWORD value; if ((GetD3DRegValue(REG_DWORD, "DisableStripFVF", &value, 4) && value != 0)) { this->m_pv->dwDeviceFlags |= D3DDEV_DONOTSTRIPELEMENTS; } } else { this->m_pv->dwMaxTextureIndices = 1; } this->dwFEFlags |= D3DFE_FRONTEND_DIRTY; #if DBG this->dwCaller=0; memset(this->dwPrimitiveType,0,sizeof(this->dwPrimitiveType)); memset(this->dwVertexType1,0,sizeof(this->dwVertexType1)); memset(this->dwVertexType2,0,sizeof(this->dwVertexType2)); #endif // True for software rendering m_dwNumStreams = __NUMSTREAMS; m_dwMaxUserClipPlanes = __MAXUSERCLIPPLANES; this->m_pv->dwClipMaskOffScreen = 0xFFFFFFFF; if (pCaps != NULL) { if (pCaps->GuardBandLeft != 0.0f || pCaps->GuardBandRight != 0.0f || pCaps->GuardBandTop != 0.0f || pCaps->GuardBandBottom != 0.0f) { this->m_pv->dwDeviceFlags |= D3DDEV_GUARDBAND; this->m_pv->dwClipMaskOffScreen = ~__D3DCS_INGUARDBAND; DWORD v; if (GetD3DRegValue(REG_DWORD, "DisableGB", &v, 4) && v != 0) { this->m_pv->dwDeviceFlags &= ~D3DDEV_GUARDBAND; this->m_pv->dwClipMaskOffScreen = 0xFFFFFFFF; } #if DBG // Try to get test values for the guard band char value[80]; if (GetD3DRegValue(REG_SZ, "GuardBandLeft", &value, 80) && value[0] != 0) sscanf(value, "%f", &pCaps->GuardBandLeft); if (GetD3DRegValue(REG_SZ, "GuardBandRight", &value, 80) && value[0] != 0) sscanf(value, "%f", &pCaps->GuardBandRight); if (GetD3DRegValue(REG_SZ, "GuardBandTop", &value, 80) && value[0] != 0) sscanf(value, "%f", &pCaps->GuardBandTop); if (GetD3DRegValue(REG_SZ, "GuardBandBottom", &value, 80) && value[0] != 0) sscanf(value, "%f", &pCaps->GuardBandBottom); #endif // DBG } } LIST_INITIALIZE(&this->specular_tables); this->specular_table = NULL; this->lightVertexFuncTable = &lightVertexTable; m_pv->lighting.activeLights = NULL; this->m_ClipStatus.ClipUnion = 0; this->m_ClipStatus.ClipIntersection = ~0; m_pv->pDDI = m_pDDI; #if DBG m_pv->pDbgMon = m_pDbgMon; #endif return S_OK; } void CD3DHal::D3DFE_Destroy() { // Destroy lighting data SpecularTable *spec; SpecularTable *spec_next; for (spec = LIST_FIRST(&this->specular_tables); spec; spec = spec_next) { spec_next = LIST_NEXT(spec,list); D3DFree(spec); } LIST_INITIALIZE(&specular_tables); delete m_pLightArray; m_pLightArray = NULL; delete m_pv; m_pv = NULL; delete m_pConvObj; m_pConvObj = NULL; if (m_clrRects) { D3DFree(m_clrRects); m_clrRects = NULL; } } /* * Generic device part destroy */ CD3DHal::~CD3DHal() { Destroy(); } void CD3DHal::Destroy() { try // Since Destroy() can be called directly by fw { //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // MUST CLEANUP AND RELEASE CURRENTLY SET TEXTURES BEFORE // DOING ANY OTHER WORK, else we will get into situations // where we are calling FlushStates or batching DDI tokens. CleanupTextures(); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /* Clear flags that could prohibit cleanup */ m_dwHintFlags &= ~(D3DDEVBOOL_HINTFLAGS_INSCENE); // Destroy vertex shaders. We need to delete vertex shaders completely // to preserve behavior for DX8.0 apps. For DX8.1 apps we delete only // PSGP part of a vertex shader. The rest will be used to re-create // the shader during Reset() if (m_pVShaderArray != NULL) { UINT size = m_pVShaderArray->GetSize(); for (UINT i=0; i < size; i++) { UINT Handle = m_pVShaderArray->HandleFromIndex(i); CVShader* pShader = (CVShader*)m_pVShaderArray->GetObject(Handle); if (pShader) { if (Enum()->GetAppSdkVersion() == D3D_SDK_VERSION_DX8) { m_pVShaderArray->ReleaseHandle(Handle, TRUE); } else { // We need to delete PSGP shader object before deleting // D3DFE_PROCESSVERTICES object, because AMD has keeps a // pointer to it inside the code object if (pShader->m_dwFlags & CVShader::SOFTWARE) { delete pShader->m_pCode; pShader->m_pCode = NULL; } } } } } // Destroy pixel shaders for DX8.0 apps to preserve trhe original behavior if (m_pPShaderArray != NULL) { UINT size = m_pPShaderArray->GetSize(); for (UINT i=0; i < size; i++) { UINT Handle = m_pPShaderArray->HandleFromIndex(i); CPShader* pShader = (CPShader*)m_pPShaderArray->GetObject(Handle); if (pShader) { if (Enum()->GetAppSdkVersion() == D3D_SDK_VERSION_DX8) { m_pPShaderArray->ReleaseHandle(Handle, TRUE); } } } } if (m_pv) { if ( 0 != m_pv->pGeometryFuncs && (LPVOID)m_pv->pGeometryFuncs != (LPVOID)GeometryFuncsGuaranteed) { delete m_pv->pGeometryFuncs; m_pv->pGeometryFuncs = 0; } if ( 0 != GeometryFuncsGuaranteed) { delete GeometryFuncsGuaranteed; GeometryFuncsGuaranteed = 0; m_pv->pGeometryFuncs = 0; } } this->D3DFE_Destroy(); if ( 0 != rstates) { delete[] rstates; rstates = 0; } delete pMatrixDirtyForDDI; pMatrixDirtyForDDI = NULL; CD3DBase::Destroy(); } catch(HRESULT ret) { DPF_ERR("There was some error when Reset()ing the device; as a result some resources may not be freed."); } } /* * Create a device. * * This method * implements the CreateDevice method of the CEnum object. (The CEnum * object exposes the IDirect3D8 interface which supports enumeration * etc.) * */ #undef DPF_MODNAME #define DPF_MODNAME "CEnum::CreateDevice" STDMETHODIMP CEnum::CreateDevice( UINT iAdapter, D3DDEVTYPE DeviceType, HWND hwndFocusWindow, DWORD dwFlags, D3DPRESENT_PARAMETERS *pPresentationParams, IDirect3DDevice8 **ppNewInterface) { API_ENTER(this); PD3D8_DEVICEDATA pDD; LPD3DBASE pd3ddev; HRESULT ret = D3D_OK; VOID* pInit = NULL; if (!VALID_PTR_PTR(ppNewInterface)) { DPF_ERR("Invalid IDirect3DDevice8* pointer, CreateDevice fails"); return D3DERR_INVALIDCALL; } // Zero out out parameters *ppNewInterface = NULL; if (!VALID_PTR(pPresentationParams, sizeof(D3DPRESENT_PARAMETERS))) { DPF_ERR("Invalid D3DPRESENT_PARAMETERS pointer, CreateDevice fails"); return D3DERR_INVALIDCALL; } // Check that fullscreen parameters are correct if (pPresentationParams->Windowed) { if (pPresentationParams->FullScreen_RefreshRateInHz != 0) { DPF_ERR("FullScreen_RefreshRateInHz must be zero for windowed mode. CreateDevice fails."); return D3DERR_INVALIDCALL; } if (pPresentationParams->FullScreen_PresentationInterval != 0) { DPF_ERR("FullScreen_PresentationInterval must be zero for windowed mode. CreateDevice fails."); return D3DERR_INVALIDCALL; } } else { DWORD interval = pPresentationParams->FullScreen_PresentationInterval; switch (interval) { case D3DPRESENT_INTERVAL_DEFAULT: case D3DPRESENT_INTERVAL_ONE: case D3DPRESENT_INTERVAL_TWO: case D3DPRESENT_INTERVAL_THREE: case D3DPRESENT_INTERVAL_FOUR: case D3DPRESENT_INTERVAL_IMMEDIATE: break; default: DPF_ERR("Invalid value for FullScreen_PresentationInterval. CreateDevice Fails."); return D3DERR_INVALIDCALL; } } if (pPresentationParams->BackBufferFormat == D3DFMT_UNKNOWN) { DPF_ERR("Invalid backbuffer format specified. CreateDevice fails."); return D3DERR_INVALIDCALL; } if (pPresentationParams->Flags & ~D3DPRESENTFLAG_LOCKABLE_BACKBUFFER) { DPF_ERR("Invalid flag for Flags. CreateDevice fails."); return D3DERR_INVALIDCALL; } // Validate the HWNDs that we are given if (hwndFocusWindow && !IsWindow(hwndFocusWindow)) { DPF_ERR("Invalid HWND specified for hwndFocusWindow, CreateDevice fails"); return D3DERR_INVALIDCALL; } if (pPresentationParams->hDeviceWindow && !IsWindow(pPresentationParams->hDeviceWindow)) { DPF_ERR("Invalid HWND specified for PresentationParams.hDeviceWindow. CreateDevice fails."); return D3DERR_INVALIDCALL; } // Make sure that we are given a focus window or a device window if (NULL == hwndFocusWindow) { if (!pPresentationParams->Windowed) { DPF_ERR("Fullscreen CreateDevice must specify Focus window"); return D3DERR_INVALIDCALL; } else if (NULL == pPresentationParams->hDeviceWindow) { DPF_ERR("Neither hDeviceWindow nor Focus window specified. CreateDevice Failed."); return D3DERR_INVALIDCALL; } } if (iAdapter >= m_cAdapter) { DPF_ERR("Invalid iAdapter parameter passed to CreateDevice"); return D3DERR_INVALIDCALL; } if (dwFlags & ~VALID_D3DCREATE_FLAGS) { DPF_ERR("Invalid BehaviorFlags passed to CreateDevice"); return D3DERR_INVALIDCALL; } // Check that exactly one of the vertex processing flags is set DWORD dwVertexProcessingFlags = dwFlags & (D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MIXED_VERTEXPROCESSING); if (dwVertexProcessingFlags != D3DCREATE_HARDWARE_VERTEXPROCESSING && dwVertexProcessingFlags != D3DCREATE_SOFTWARE_VERTEXPROCESSING && dwVertexProcessingFlags != D3DCREATE_MIXED_VERTEXPROCESSING) { DPF_ERR("Invalid Flags parameter to CreateDevice: Exactly One of the" " following must be set: D3DCREATE_HARDWARE_VERTEXPROCESSING," " D3DCREATE_SOFTWARE_VERTEXPROCESSING or" " D3DCREATE_MIXED_VERTEXPROCESSING"); return D3DERR_INVALIDCALL; } if (DeviceType == D3DDEVTYPE_SW) { pInit = m_pSwInitFunction; if (pInit == NULL) { D3D_ERR("App specified D3DDEVTYPE_SW without first registering a software device. CreateDevice Failed."); return D3DERR_INVALIDCALL; } GetSwCaps(iAdapter); } else if (DeviceType == D3DDEVTYPE_REF) { GetRefCaps(iAdapter); } ret = InternalDirectDrawCreate(&pDD, &m_AdapterInfo[iAdapter], DeviceType, pInit, GetUnknown16(iAdapter), m_AdapterInfo[iAdapter].HALCaps.pGDD8SupportedFormatOps, m_AdapterInfo[iAdapter].HALCaps.GDD8NumSupportedFormatOps); if( FAILED(ret) ) { D3D_ERR("Failed to create DirectDraw. CreateDevice Failed."); return ret; } if((dwFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) != 0) { if((dwFlags & D3DCREATE_PUREDEVICE) != 0) { D3D_ERR("Pure device cannot perform software processing. CreateDevice Failed."); InternalDirectDrawRelease(pDD); return D3DERR_INVALIDCALL; } } else if((dwFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0) { if((pDD->DriverData.D3DCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0) { D3D_ERR("Device cannot perform hardware processing"); InternalDirectDrawRelease(pDD); return D3DERR_INVALIDCALL; } } else if((dwFlags & D3DCREATE_MIXED_VERTEXPROCESSING) != 0) { if((pDD->DriverData.D3DCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 || (dwFlags & D3DCREATE_PUREDEVICE) != 0) { D3D_ERR("Device cannot perform mixed processing because driver cannot do hardware T&L. CreateDevice Failed."); InternalDirectDrawRelease(pDD); return D3DERR_INVALIDCALL; } } else { if((dwFlags & D3DCREATE_PUREDEVICE) != 0) { if((pDD->DriverData.D3DCaps.DevCaps & D3DDEVCAPS_PUREDEVICE) == 0) { D3D_ERR("Hardware should be capable of creating a pure device"); InternalDirectDrawRelease(pDD); return D3DERR_INVALIDCALL; } } else { D3D_ERR("Must specify software, hardware or mixed vertex processing"); InternalDirectDrawRelease(pDD); return D3DERR_INVALIDCALL; } } switch (DeviceType) { case D3DDEVTYPE_SW: case D3DDEVTYPE_REF: case D3DDEVTYPE_HAL: if (dwFlags & D3DCREATE_PUREDEVICE) { pd3ddev = new CD3DBase(); } else { pd3ddev = static_cast(new CD3DHal()); } break; default: D3D_ERR("Unrecognized or unsupported DeviceType. CreateDevice Failed."); InternalDirectDrawRelease(pDD); return D3DERR_INVALIDCALL; } if (!pd3ddev) { D3D_ERR("Failed to allocate space for the device object. CreateDevice Failed."); InternalDirectDrawRelease(pDD); return (E_OUTOFMEMORY); } #if DBG { char DevTypeMsg[256]; _snprintf( DevTypeMsg, 256, "=======================" ); switch( DeviceType ) { case D3DDEVTYPE_HAL: _snprintf( DevTypeMsg, 256, "%s Hal", DevTypeMsg ); break; case D3DDEVTYPE_SW: _snprintf( DevTypeMsg, 256, "%s Pluggable SW", DevTypeMsg ); break; case D3DDEVTYPE_REF: _snprintf( DevTypeMsg, 256, "%s Reference", DevTypeMsg ); break; default: _snprintf( DevTypeMsg, 256, "%s Unknown", DevTypeMsg ); break; } if (dwFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) { _snprintf( DevTypeMsg, 256, "%s HWVP", DevTypeMsg ); } else if (dwFlags & D3DCREATE_MIXED_VERTEXPROCESSING) { _snprintf( DevTypeMsg, 256, "%s MixedVP", DevTypeMsg ); } else if (dwFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING) { _snprintf( DevTypeMsg, 256, "%s SWVP", DevTypeMsg ); } if (dwFlags & D3DCREATE_PUREDEVICE) { _snprintf( DevTypeMsg, 256, "%s Pure", DevTypeMsg ); } _snprintf( DevTypeMsg, 256, "%s device selected", DevTypeMsg ); D3D_INFO( 0, DevTypeMsg ); } #endif // // FW's Init // ret = static_cast(pd3ddev)->Init( pDD, DeviceType, hwndFocusWindow, dwFlags, pPresentationParams, iAdapter, this); if (FAILED(ret)) { D3D_ERR("Failed to initialize Framework Device. CreateDevice Failed."); delete pd3ddev; return ret; } // We try and create a dummy vidmem vertexbuffer. If this doesn't // succeed, we just turn off vidmem VBs. This is to work around // the Rage 128 driver that reports DDERR_OUTOFVIDEOMEMORY even // though it simply doesn't support vidmem VBs if(!IS_DX8HAL_DEVICE(pd3ddev)) { #ifdef WIN95 //ON 9x we probe to see if the driver can do vidmem VBs... CVertexBuffer *pVertexBuffer; ret = CVertexBuffer::CreateDriverVertexBuffer(pd3ddev, 1024, D3DFVF_TLVERTEX, D3DUSAGE_WRITEONLY | D3DUSAGE_DONOTCLIP, D3DUSAGE_WRITEONLY | D3DUSAGE_DONOTCLIP | D3DUSAGE_LOCK, D3DPOOL_DEFAULT, D3DPOOL_DEFAULT, REF_INTERNAL, &pVertexBuffer); if(FAILED(ret)) { if(pd3ddev->VBFailOversDisabled()) { DPF_ERR("Cannot create Vidmem vertex buffer. Will ***NOT*** failover to Sysmem."); return ret; } DPF(1,"Driver doesnt support VidMemVBs which is fine"); } else { // Get rid of the vb pVertexBuffer->DecrementUseCount(); pd3ddev->EnableVidmemVBs(); } #else //WIN95 //On NT we require the drivers to tell us (by setting D3DDEVCAPS_HWVERTEXBUFFER) //Turn off DX7 driver VBs on NT if asked to do so... DWORD value; if ((GetD3DRegValue(REG_DWORD, "DisableVidMemVBs", &value, 4) != 0) && (value != 0)) { pd3ddev->DisableVidmemVBs(); } #endif //!WIN95 } ret = pd3ddev->Init(); if (ret != D3D_OK) { delete pd3ddev; D3D_ERR("Failed to initialize D3DDevice. CreateDevice Failed."); return ret; } // Looks like everything is in order *ppNewInterface = static_cast(pd3ddev); #ifdef APIPROF CApiProfileDevice* profile = new CApiProfileDevice; if (profile) { if (profile->Init() == D3D_OK) { profile->SetDevice(*ppNewInterface); *ppNewInterface = static_cast(profile); } else { delete profile; } } #endif // APIPROF return S_OK; } #ifdef _X86_ // -------------------------------------------------------------------------- // Detect 3D extensions // -------------------------------------------------------------------------- BOOL _asm_isX3D() { DWORD retval = 0; _asm { pushad ; CPUID trashes lots - save everything mov eax,80000000h ; Check for extended CPUID support ;;; We need to upgrade our compiler ;;; CPUID == 0f,a2 _emit 0x0f _emit 0xa2 cmp eax,80000001h ; Jump if no extended CPUID jb short done ; mov eax,80000001h ; Check for feature ;;; CPUID == 0f,a2 _emit 0x0f _emit 0xa2 xor eax,eax ; test edx,80000000h ; setnz al ; mov retval,eax ; done: popad ; Restore everything }; return retval; } static BOOL isX3Dprocessor(void) { __try { if( _asm_isX3D() ) { return TRUE; } } __except(GetExceptionCode() == STATUS_ILLEGAL_INSTRUCTION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { } return FALSE; } //--------------------------------------------------------------------- // Detects Intel SSE processor // #pragma optimize("", off) #define CPUID _asm _emit 0x0f _asm _emit 0xa2 #define SSE_PRESENT 0x02000000 // bit number 25 #define WNI_PRESENT 0x04000000 // bit number 26 DWORD IsIntelSSEProcessor(void) { DWORD retval = 0; DWORD RegisterEAX; DWORD RegisterEDX; char VendorId[12]; const char IntelId[13]="GenuineIntel"; __try { _asm { xor eax,eax CPUID mov RegisterEAX, eax mov dword ptr VendorId, ebx mov dword ptr VendorId+4, edx mov dword ptr VendorId+8, ecx } } __except (1) { return retval; } // make sure EAX is > 0 which means the chip // supports a value >=1. 1 = chip info if (RegisterEAX == 0) return retval; // this CPUID can't fail if the above test passed __asm { mov eax,1 CPUID mov RegisterEAX,eax mov RegisterEDX,edx } if (RegisterEDX & SSE_PRESENT) { retval |= D3DCPU_SSE; } if (RegisterEDX & WNI_PRESENT) { retval |= D3DCPU_WLMT; } return retval; } #pragma optimize("", on) // IsProcessorFeatureAvailable() is supported only by WINNT. For other OS // we emulate it #ifdef WINNT static BOOL D3DIsProcessorFeaturePresent(UINT feature) { switch (feature) { // WINNT does not recognize Willamette processor when we use // PF_XMMI64_INSTRUCTIONS_AVAILABLE, so use our detection instead case PF_XMMI64_INSTRUCTIONS_AVAILABLE: { DWORD flags = IsIntelSSEProcessor(); return flags & D3DCPU_WLMT; } default: return IsProcessorFeaturePresent(feature); } } #else #define PF_XMMI_INSTRUCTIONS_AVAILABLE 6 #define PF_3DNOW_INSTRUCTIONS_AVAILABLE 7 #define PF_XMMI64_INSTRUCTIONS_AVAILABLE 10 static BOOL D3DIsProcessorFeaturePresent(UINT feature) { switch (feature) { case PF_XMMI_INSTRUCTIONS_AVAILABLE: { if (IsWin95()) return FALSE; DWORD flags = IsIntelSSEProcessor(); return flags & D3DCPU_SSE; } case PF_3DNOW_INSTRUCTIONS_AVAILABLE: return isX3Dprocessor(); case PF_XMMI64_INSTRUCTIONS_AVAILABLE: { if (IsWin95()) return FALSE; DWORD flags = IsIntelSSEProcessor(); return flags & D3DCPU_WLMT; } default: return FALSE; } } #endif // WINNT #endif // _X86_ //------------------------------------------------------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::InitDevice" HRESULT CD3DHal::InitDevice() { HRESULT ret; // Initialize values so we don't crash at shutdown this->GeometryFuncsGuaranteed = NULL; this->rstates = NULL; m_pLightArray = NULL; m_pv = NULL; m_pCurrentShader = NULL; m_pConvObj = NULL; pMatrixDirtyForDDI = NULL; m_clrRects = NULL; m_clrCount = 0; m_pv = new D3DFE_PROCESSVERTICES; if (m_pv == NULL) { D3D_ERR("Could not allocate the FE/PSGP data structure (D3DFE_PROCESSVERTICES)."); return E_OUTOFMEMORY; } m_pv->pGeometryFuncs = NULL; ret = CD3DBase::InitDevice(); if (ret != D3D_OK) { D3D_ERR("Failed to initialize CD3DBase."); return(ret); } pMatrixDirtyForDDI = new CPackedBitArray; if( pMatrixDirtyForDDI == NULL ) { D3D_ERR("Could not allocate memory for internal data structure pMatrixDirtyForDDI."); return E_OUTOFMEMORY; } if (FAILED(rsVec.Init(D3D_MAXRENDERSTATES)) || FAILED(rsVecRetired.Init(D3D_MAXRENDERSTATES)) || FAILED(rsVertexProcessingOnly.Init(D3D_MAXRENDERSTATES)) || FAILED(pMatrixDirtyForDDI->Init(D3D_MAXTRANSFORMSTATES))) { D3D_ERR("Could not allocate memory for renderstate processing bit vectors"); return E_OUTOFMEMORY; } m_pLightArray = new CHandleArray; if (m_pLightArray == NULL) { D3D_ERR("Could not allocate memory for internal data structure m_pLightArray"); return E_OUTOFMEMORY; } dwFEFlags = 0; // Initialize FEFlags content that depends on DDI type if ( (GetDDIType() == D3DDDITYPE_DX7TL) || (GetDDIType() == D3DDDITYPE_DX8TL) ) dwFEFlags |= D3DFE_TLHAL; // Since this is HAL, initialize it to use the software pipeline // this will be turned off when the SW/HW renderstate is set. m_pv->dwVIDIn = 0; m_pv->pD3DMappedTexI = (LPVOID*)(m_lpD3DMappedTexI); /*------------------------------------------------------------------------- * Up till now we have done the easy part of the initialization. This is * the stuff that cannot fail. It initializes the object so that the * destructor can be safely called if any of the further initialization * does not succeed. *-----------------------------------------------------------------------*/ this->GeometryFuncsGuaranteed = new D3DFE_PVFUNCSI; if (this->GeometryFuncsGuaranteed == NULL) { D3D_ERR("Could not allocate memory for internal data structure GeometryFuncsGuaranteed"); return E_OUTOFMEMORY; } // Software constant register buffer must handle all constants, provided by // hardware, to make Set/Get constants possible this->GeometryFuncsGuaranteed->m_VertexVM.Init(GetD3DCaps()->MaxVertexShaderConst); m_pv->pGeometryFuncs = (LPD3DFE_PVFUNCS)GeometryFuncsGuaranteed; if (this->GeometryFuncsGuaranteed == NULL) { D3D_ERR("Could not allocate memory for FE/PSGP function table."); return D3DERR_INVALIDCALL; } // set up flag to use MMX when requested RGB BOOL bUseMMXAsRGBDevice = FALSE; D3DSURFACE_DESC desc = this->RenderTarget()->InternalGetDesc(); /* * Check if the 3D cap is set on the surface. */ if ((desc.Usage & D3DUSAGE_RENDERTARGET) == 0) { D3D_ERR("**** The D3DUSAGE_RENDERTARGET is not set on this surface."); D3D_ERR("**** You need to add D3DUSAGE_RENDERTARGET to the Usage parameter"); D3D_ERR("**** when creating the surface."); return (D3DERR_INVALIDCALL); } // Create front-end support structures. ret = this->D3DFE_Create(); if (ret != D3D_OK) { D3D_ERR("Failed to create front-end data-structures."); goto handle_err; } // In all other cases we simply allocate memory for rstates rstates = new DWORD[D3D_MAXRENDERSTATES]; m_pv->lpdwRStates = this->rstates; #ifndef PROFILE4 #ifdef _X86_ if ((ULONG_PTR)&m_pv->view & 0xF) { char s[256]; sprintf(s, "0%xh \n", (ULONG_PTR)&m_pv->view); OutputDebugString("INTERNAL ERROR:View matrix in D3DFE_PROCESSVERTICES structure must be aligned to 16 bytes\n"); OutputDebugString(s); ret = D3DERR_INVALIDCALL; goto handle_err; } // Check if we have a processor specific implementation available // only use if DisablePSGP is not in registry or set to zero DWORD value; if (!GetD3DRegValue(REG_DWORD, "DisablePSGP", &value, sizeof(DWORD))) { value = 0; } #if DBG if (m_pDbgMon && m_pDbgMon->MonitorConnected()) { value = 1; } #endif // value = // 0 - PSGP enabled // 1 - PSGP disabled // 2 - X3D PSGP disabled if (value != 1) { // Ask the PV implementation to create a device specific "context" LPD3DFE_PVFUNCS pOptGeoFuncs = m_pv->pGeometryFuncs; // TODO (bug 40438): Remove DLL interface for final // Try to use PSGP DLL first if (pfnFEContextCreate) { ret = pfnFEContextCreate(m_pv->dwDeviceFlags, &pOptGeoFuncs); if ((ret == D3D_OK) && pOptGeoFuncs) { D3D_INFO(0, "Using PSGP DLL"); m_pv->pGeometryFuncs = pOptGeoFuncs; goto l_chosen; } } if (D3DIsProcessorFeaturePresent(PF_3DNOW_INSTRUCTIONS_AVAILABLE) && value != 2) { ret = x3DContextCreate(m_pv->dwDeviceFlags, &pOptGeoFuncs); if (ret == S_OK && pOptGeoFuncs) { D3D_INFO(0, "Using X3D PSGP"); m_pv->pGeometryFuncs = pOptGeoFuncs; goto l_chosen; } } if (D3DIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE)) { ret = wlmt_FEContextCreate(m_pv->dwDeviceFlags, &pOptGeoFuncs); if (ret == S_OK && pOptGeoFuncs) { D3D_INFO(0, "Using WLMT PSGP"); m_pv->pGeometryFuncs = pOptGeoFuncs; goto l_chosen; } } if (D3DIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE)) { ret = katmai_FEContextCreate(m_pv->dwDeviceFlags, &pOptGeoFuncs); if (ret == S_OK && pOptGeoFuncs) { D3D_INFO(0, "Using P3 PSGP"); m_pv->pGeometryFuncs = pOptGeoFuncs; goto l_chosen; } } l_chosen:; } #endif // _X86_ #endif // PROFILE4 { if (HVbuf.Grow((__INIT_VERTEX_NUMBER*2)*sizeof(D3DFE_CLIPCODE)) != DD_OK) { D3D_ERR( "Could not allocate memory for internal buffer HVBuf" ); ret = E_OUTOFMEMORY; goto handle_err; } } // Setup lights if( FAILED( m_pLightArray->Grow( 8 ) ) ) { D3D_ERR( "Could not allocate memory for the light array" ); ret = E_OUTOFMEMORY; goto handle_err; } LIST_INITIALIZE(&m_ActiveLights); // Setup material memset(&m_pv->lighting.material, 0, sizeof(m_pv->lighting.material)); // Set viewport to update front-end data SetViewportI(&m_Viewport); m_pv->PointSizeMax = GetD3DCaps()->MaxPointSize; { DWORD EmulatePointSprites = 1; GetD3DRegValue(REG_DWORD, "EmulatePointSprites", &EmulatePointSprites, sizeof(DWORD)); if ((m_pv->PointSizeMax == 0 || !(GetD3DCaps()->FVFCaps & D3DFVFCAPS_PSIZE)) && EmulatePointSprites) { m_dwRuntimeFlags |= D3DRT_DOPOINTSPRITEEMULATION; if (m_pv->PointSizeMax == 0) m_pv->PointSizeMax = __MAX_POINT_SIZE; else m_dwRuntimeFlags |= D3DRT_SUPPORTSPOINTSPRITES; } } m_pfnPrepareToDraw = NULL; return (D3D_OK); handle_err: return(ret); } //--------------------------------------------------------------------- DWORD ProcessRects(CD3DHal* pDevI, DWORD dwCount, CONST D3DRECT* rects) { RECT vwport; DWORD i,j; /* * Rip through the rects and validate that they * are within the viewport. */ if (dwCount == 0 && rects == NULL) { dwCount = 1; } #if DBG else if (rects == NULL) { D3D_ERR("The rects parameter is NULL."); throw D3DERR_INVALIDCALL; } #endif if (dwCount > pDevI->m_clrCount) { LPD3DRECT newRects; if (D3D_OK == D3DMalloc((void**)&newRects, dwCount * sizeof(D3DRECT))) { memcpy((void*)newRects,(void*)pDevI->m_clrRects, pDevI->m_clrCount* sizeof(D3DRECT)); D3DFree((LPVOID)pDevI->m_clrRects); pDevI->m_clrRects = newRects; } else { pDevI->m_clrCount = 0; D3DFree((LPVOID)pDevI->m_clrRects); pDevI->m_clrRects = NULL; D3D_ERR("failed to allocate space for rects"); throw E_OUTOFMEMORY; } } pDevI->m_clrCount = dwCount; // If nothing is specified, assume the viewport needs to be cleared if (!rects) { pDevI->m_clrRects[0].x1 = pDevI->m_Viewport.X; pDevI->m_clrRects[0].y1 = pDevI->m_Viewport.Y; pDevI->m_clrRects[0].x2 = pDevI->m_Viewport.X + pDevI->m_Viewport.Width; pDevI->m_clrRects[0].y2 = pDevI->m_Viewport.Y + pDevI->m_Viewport.Height; return 1; } else { vwport.left = pDevI->m_Viewport.X; vwport.top = pDevI->m_Viewport.Y; vwport.right = pDevI->m_Viewport.X + pDevI->m_Viewport.Width; vwport.bottom = pDevI->m_Viewport.Y + pDevI->m_Viewport.Height; j=0; for (i = 0; i < dwCount; i++) { if (IntersectRect((LPRECT)(pDevI->m_clrRects + j), &vwport, (LPRECT)(rects + i))) j++; } return j; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "CD3DHal::ClearI" void CD3DHal::ClearI(DWORD dwCount, CONST D3DRECT* rects, DWORD dwFlags, D3DCOLOR dwColor, D3DVALUE dvZ, DWORD dwStencil) { dwCount = ProcessRects(this, dwCount, rects); // Device should never receive 0 count, because for Pure device this // means "clear whole viewport" if (dwCount != 0) { // Call DDI specific Clear routine m_pDDI->Clear(dwFlags, dwCount, m_clrRects, dwColor, dvZ, dwStencil); } }