diff --git a/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DSmudge.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DSmudge.h index 3ebba960043..080dec5759f 100644 --- a/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DSmudge.h +++ b/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DSmudge.h @@ -55,9 +55,7 @@ class W3DSmudgeManager : public SmudgeManager ShareBufferClass *m_RGBABuffer; ///< array of particle color and alpha ShareBufferClass *m_sizeBuffer; ///< array of particle sizes -#ifdef USE_COPY_RECTS TextureClass *m_backgroundTexture; -#endif DX8IndexBufferClass *m_indexBuffer; Int m_backBufferWidth; Int m_backBufferHeight; diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp index 87fa12f5c29..7ab211a991f 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp @@ -173,13 +173,11 @@ Int ScreenDefaultFilter::init() Bool ScreenDefaultFilter::preRender(Bool &skipRender, CustomScenePassModes &scenePassMode) { - //Right now this filter is only used for smudges, so don't bother if none are present. - if (TheSmudgeManager) - { if (((W3DSmudgeManager *)TheSmudgeManager)->getSmudgeCountLastFrame() == 0) - return FALSE; - } - W3DShaderManager::startRenderToTexture(); - return true; + // TheSuperHackers @bugfix Disable Render To Texture redirection for the default filter + // When MSAA is forced by Nvidia driver profile depth buffer is multisampled internally + // Rendering to non-MSAA texture with this depth buffer corrupts depth testing producing black screen + // The smudge system has its own Copy path that works without Render To Texture + return FALSE; } Bool ScreenDefaultFilter::postRender(FilterModes mode, Coord2D &scrollDelta,Bool &doExtraRender) @@ -2604,30 +2602,39 @@ void W3DShaderManager::init() //Some of our effects require an offscreen render target, so try creating it here. HRESULT hr=DX8Wrapper::_Get_D3D_Device8()->GetRenderTarget(&m_oldRenderSurface); - m_oldRenderSurface->GetDesc(&desc); + if (hr != S_OK || !m_oldRenderSurface) + return; - hr=DX8Wrapper::_Get_D3D_Device8()->CreateTexture(desc.Width,desc.Height,1,D3DUSAGE_RENDERTARGET,desc.Format,D3DPOOL_DEFAULT,&m_renderTexture); + m_oldRenderSurface->GetDesc(&desc); + + // TheSuperHackers @bugfix Redirecting rendering to a non-multisampled texture + // while using a multisampled depth buffer is an API violation in DX8. + if (desc.MultiSampleType == D3DMULTISAMPLE_NONE) + { + hr=DX8Wrapper::_Get_D3D_Device8()->CreateTexture(desc.Width,desc.Height,1,D3DUSAGE_RENDERTARGET,desc.Format,D3DPOOL_DEFAULT,&m_renderTexture); + } + else + { + // Force failure path to avoid MSAA mismatch + hr = E_FAIL; + } if (hr != S_OK) { - if (m_oldRenderSurface) m_oldRenderSurface->Release(); - m_oldRenderSurface = nullptr; + SAFE_RELEASE(m_oldRenderSurface); m_renderTexture = nullptr; } else { hr = m_renderTexture->GetSurfaceLevel(0, &m_newRenderSurface); if (hr != S_OK) { - if (m_renderTexture) m_renderTexture->Release(); - m_renderTexture = nullptr; + SAFE_RELEASE(m_renderTexture); m_newRenderSurface = nullptr; } else { hr = DX8Wrapper::_Get_D3D_Device8()->GetDepthStencilSurface(&m_oldDepthSurface); if (hr != S_OK) { - if (m_newRenderSurface) m_newRenderSurface->Release(); - if (m_renderTexture) m_renderTexture->Release(); - m_renderTexture = nullptr; - m_newRenderSurface = nullptr; + SAFE_RELEASE(m_newRenderSurface); + SAFE_RELEASE(m_renderTexture); m_oldDepthSurface = nullptr; } } @@ -2665,14 +2672,10 @@ void W3DShaderManager::init() //============================================================================= void W3DShaderManager::shutdown() { - if (m_newRenderSurface) m_newRenderSurface->Release(); - if (m_renderTexture) m_renderTexture->Release(); - if (m_oldRenderSurface) m_oldRenderSurface->Release(); - if (m_oldDepthSurface) m_oldDepthSurface->Release(); - m_renderTexture = nullptr; - m_newRenderSurface = nullptr; - m_oldDepthSurface = nullptr; - m_oldRenderSurface = nullptr; + SAFE_RELEASE(m_newRenderSurface); + SAFE_RELEASE(m_renderTexture); + SAFE_RELEASE(m_oldRenderSurface); + SAFE_RELEASE(m_oldDepthSurface); m_currentShader = ST_INVALID; m_currentFilter = FT_NULL_FILTER; //release any assets associated with a shader (vertex/pixel shaders, textures, etc.) @@ -2831,9 +2834,20 @@ void W3DShaderManager::startRenderToTexture() if (m_renderingToTexture || m_newRenderSurface==nullptr || m_oldDepthSurface==nullptr) return; HRESULT hr = DX8Wrapper::_Get_D3D_Device8()->SetRenderTarget(m_newRenderSurface,m_oldDepthSurface); - DEBUG_ASSERTCRASH(hr==S_OK, ("Set target failed unexpectedly.")); + + // TheSuperHackers @bugfix If SetRenderTarget fails (e.g. due to MSAA forced by driver + // profile causing a depth buffer mismatch that D3DSURFACE_DESC doesn't report), permanently + // disable RTT to prevent repeated failures and accidental backbuffer clears. if (hr != S_OK) + { + // Permanently disable RTT + SAFE_RELEASE(m_newRenderSurface); + SAFE_RELEASE(m_renderTexture); + SAFE_RELEASE(m_oldRenderSurface); + SAFE_RELEASE(m_oldDepthSurface); return; + } + m_renderingToTexture = true; if (TheGlobalData->m_showSoftWaterEdge) { //Soft water edges use frame buffer destination alpha so we must clear it to a known value. diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DSmudge.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DSmudge.cpp index 9fde80ea320..2fc281d2198 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DSmudge.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DSmudge.cpp @@ -66,9 +66,7 @@ void W3DSmudgeManager::reset () void W3DSmudgeManager::ReleaseResources() { -#ifdef USE_COPY_RECTS REF_PTR_RELEASE(m_backgroundTexture); -#endif REF_PTR_RELEASE(m_indexBuffer); } @@ -85,9 +83,7 @@ void W3DSmudgeManager::ReAcquireResources() surface->Get_Description(surface_desc); REF_PTR_RELEASE(surface); - #ifdef USE_COPY_RECTS - m_backgroundTexture = MSGNEW("TextureClass") TextureClass(TheTacticalView->getWidth(),TheTacticalView->getHeight(),surface_desc.Format,MIP_LEVELS_1,TextureClass::POOL_DEFAULT, true); - #endif + m_backgroundTexture = MSGNEW("TextureClass") TextureClass(surface_desc.Width,surface_desc.Height,surface_desc.Format,MIP_LEVELS_1,TextureClass::POOL_DEFAULT, true); m_backBufferWidth = surface_desc.Width; m_backBufferHeight = surface_desc.Height; @@ -207,15 +203,19 @@ Bool W3DSmudgeManager::testHardwareSupport() { //we have not done the test yet. IDirect3DTexture8 *backTexture=W3DShaderManager::getRenderTexture(); - if (!backTexture) - { //do trivial test first to see if render target exists. + if (!backTexture || !W3DShaderManager::isRenderingToTexture()) + { + // TheSuperHackers @bugfix When RTT is disabled globally accept the Copy path as hardware support + if (m_backgroundTexture) + { + m_hardwareSupportStatus = SMUDGE_SUPPORT_YES; + return TRUE; + } + m_hardwareSupportStatus = SMUDGE_SUPPORT_NO; return FALSE; } - if (!W3DShaderManager::isRenderingToTexture()) - return FALSE; //can't do the test unless we're rendering to texture. - VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); DX8Wrapper::Set_Material(vmat); REF_PTR_RELEASE(vmat); //no need to keep a reference since it's a preset. @@ -306,6 +306,22 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo) if (!testHardwareSupport()) return; + SurfaceClass *backBuffer = DX8Wrapper::_Get_DX8_Back_Buffer(); + + if (!backBuffer) + return; + + SurfaceClass *background=m_backgroundTexture ? m_backgroundTexture->Get_Surface_Level() : nullptr; + + if (!background) + { + REF_PTR_RELEASE(backBuffer); + return; + } + + SurfaceClass::SurfaceDescription surface_desc; + backBuffer->Get_Description(surface_desc); + CameraClass &camera=rinfo.Camera; Vector3 vsVert; Vector4 ssVert; @@ -327,23 +343,6 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo) camera.Get_View_Matrix(&view); camera.Get_Projection_Matrix(&proj); - SurfaceClass::SurfaceDescription surface_desc; -#ifdef USE_COPY_RECTS - SurfaceClass *background=m_backgroundTexture->Get_Surface_Level(); - background->Get_Description(surface_desc); -#else - D3DSURFACE_DESC D3DDesc; - - IDirect3DTexture8 *backTexture=W3DShaderManager::getRenderTexture(); - if (!backTexture || !W3DShaderManager::isRenderingToTexture()) - return; //this card doesn't support render targets. - - backTexture->GetLevelDesc(0,&D3DDesc); - - surface_desc.Width = D3DDesc.Width; - surface_desc.Height = D3DDesc.Height; -#endif - Real texClampX = (Real)TheTacticalView->getWidth()/(Real)surface_desc.Width; Real texClampY = (Real)TheTacticalView->getHeight()/(Real)surface_desc.Height; @@ -421,23 +420,16 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo) if (!count) { -#ifdef USE_COPY_RECTS REF_PTR_RELEASE(background); -#endif + REF_PTR_RELEASE(backBuffer); return; //nothing to render. } -#ifdef USE_COPY_RECTS - SurfaceClass *backBuffer=DX8Wrapper::_Get_DX8_Back_Buffer(); - - backBuffer->Get_Description(surface_desc); - //Copy the area of backbuffer occupied by smudges into an alternate buffer. background->Copy(0,0,0,0,surface_desc.Width,surface_desc.Height,backBuffer); REF_PTR_RELEASE(background); REF_PTR_RELEASE(backBuffer); -#endif Matrix4x4 identity(true); DX8Wrapper::Set_Transform(D3DTS_WORLD,identity); @@ -447,10 +439,8 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo) //DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueSpriteShader); DX8Wrapper::Set_Shader(ShaderClass::_PresetAlphaShader); -#ifdef USE_COPY_RECTS + DX8Wrapper::Set_Texture(0,m_backgroundTexture); -#else - DX8Wrapper::Set_DX8_Texture(0,backTexture); //Need these states in case texture is non-power-of-2 DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); @@ -458,7 +448,6 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo) DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR); DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR); DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_MIPFILTER, D3DTEXF_NONE); -#endif VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); DX8Wrapper::Set_Material(vmat); REF_PTR_RELEASE(vmat); diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp index 1e26c2d0381..3b99c8d389c 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp @@ -165,8 +165,6 @@ static ShaderClass blendStagesShader(SC_DETAIL_BLEND); WaterRenderObjClass *TheWaterRenderObj=nullptr; ///Release(); (p)=nullptr; } } - void doSkyBoxSet(Bool startDraw) { if (TheWritableGlobalData) diff --git a/Core/Libraries/Source/WWVegas/WWLib/WWCommon.h b/Core/Libraries/Source/WWVegas/WWLib/WWCommon.h index d36f6df963d..7e923a41dbf 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/WWCommon.h +++ b/Core/Libraries/Source/WWVegas/WWLib/WWCommon.h @@ -23,6 +23,7 @@ #include "stringex.h" #include +#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=nullptr; } } // This macro serves as a general way to determine the number of elements within an array. #ifndef ARRAY_SIZE