Skip to content

Commit 6da321a

Browse files
authored
bugfix(smudge): Fix Microwave Heat Haze blackout on forced AA (#2374)
1 parent e18c47f commit 6da321a

5 files changed

Lines changed: 72 additions & 69 deletions

File tree

Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DSmudge.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,7 @@ class W3DSmudgeManager : public SmudgeManager
5555
ShareBufferClass<unsigned int> *m_RGBABuffer; ///< array of particle color and alpha
5656
ShareBufferClass<float> *m_sizeBuffer; ///< array of particle sizes
5757

58-
#ifdef USE_COPY_RECTS
5958
TextureClass *m_backgroundTexture;
60-
#endif
6159
DX8IndexBufferClass *m_indexBuffer;
6260
Int m_backBufferWidth;
6361
Int m_backBufferHeight;

Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,11 @@ Int ScreenDefaultFilter::init()
173173

174174
Bool ScreenDefaultFilter::preRender(Bool &skipRender, CustomScenePassModes &scenePassMode)
175175
{
176-
//Right now this filter is only used for smudges, so don't bother if none are present.
177-
if (TheSmudgeManager)
178-
{ if (((W3DSmudgeManager *)TheSmudgeManager)->getSmudgeCountLastFrame() == 0)
179-
return FALSE;
180-
}
181-
W3DShaderManager::startRenderToTexture();
182-
return true;
176+
// TheSuperHackers @bugfix Disable Render To Texture redirection for the default filter
177+
// When MSAA is forced by Nvidia driver profile depth buffer is multisampled internally.
178+
// Rendering to non-MSAA texture with this depth buffer corrupts depth testing producing black screen
179+
// The smudge system has its own Copy path that works without Render To Texture.
180+
return FALSE;
183181
}
184182

185183
Bool ScreenDefaultFilter::postRender(FilterModes mode, Coord2D &scrollDelta,Bool &doExtraRender)
@@ -2604,30 +2602,39 @@ void W3DShaderManager::init()
26042602
//Some of our effects require an offscreen render target, so try creating it here.
26052603
HRESULT hr=DX8Wrapper::_Get_D3D_Device8()->GetRenderTarget(&m_oldRenderSurface);
26062604

2607-
m_oldRenderSurface->GetDesc(&desc);
2605+
if (hr != S_OK || !m_oldRenderSurface)
2606+
return;
26082607

2609-
hr=DX8Wrapper::_Get_D3D_Device8()->CreateTexture(desc.Width,desc.Height,1,D3DUSAGE_RENDERTARGET,desc.Format,D3DPOOL_DEFAULT,&m_renderTexture);
2608+
m_oldRenderSurface->GetDesc(&desc);
2609+
2610+
// TheSuperHackers @bugfix Redirecting rendering to a non-multisampled texture
2611+
// while using a multisampled depth buffer is an API violation in DX8.
2612+
if (desc.MultiSampleType == D3DMULTISAMPLE_NONE)
2613+
{
2614+
hr=DX8Wrapper::_Get_D3D_Device8()->CreateTexture(desc.Width,desc.Height,1,D3DUSAGE_RENDERTARGET,desc.Format,D3DPOOL_DEFAULT,&m_renderTexture);
2615+
}
2616+
else
2617+
{
2618+
// Force failure path to avoid MSAA mismatch
2619+
hr = E_FAIL;
2620+
}
26102621

26112622
if (hr != S_OK)
26122623
{
2613-
if (m_oldRenderSurface) m_oldRenderSurface->Release();
2614-
m_oldRenderSurface = nullptr;
2624+
SAFE_RELEASE(m_oldRenderSurface);
26152625
m_renderTexture = nullptr;
26162626
} else {
26172627
hr = m_renderTexture->GetSurfaceLevel(0, &m_newRenderSurface);
26182628
if (hr != S_OK)
26192629
{
2620-
if (m_renderTexture) m_renderTexture->Release();
2621-
m_renderTexture = nullptr;
2630+
SAFE_RELEASE(m_renderTexture);
26222631
m_newRenderSurface = nullptr;
26232632
} else {
26242633
hr = DX8Wrapper::_Get_D3D_Device8()->GetDepthStencilSurface(&m_oldDepthSurface);
26252634
if (hr != S_OK)
26262635
{
2627-
if (m_newRenderSurface) m_newRenderSurface->Release();
2628-
if (m_renderTexture) m_renderTexture->Release();
2629-
m_renderTexture = nullptr;
2630-
m_newRenderSurface = nullptr;
2636+
SAFE_RELEASE(m_newRenderSurface);
2637+
SAFE_RELEASE(m_renderTexture);
26312638
m_oldDepthSurface = nullptr;
26322639
}
26332640
}
@@ -2665,14 +2672,10 @@ void W3DShaderManager::init()
26652672
//=============================================================================
26662673
void W3DShaderManager::shutdown()
26672674
{
2668-
if (m_newRenderSurface) m_newRenderSurface->Release();
2669-
if (m_renderTexture) m_renderTexture->Release();
2670-
if (m_oldRenderSurface) m_oldRenderSurface->Release();
2671-
if (m_oldDepthSurface) m_oldDepthSurface->Release();
2672-
m_renderTexture = nullptr;
2673-
m_newRenderSurface = nullptr;
2674-
m_oldDepthSurface = nullptr;
2675-
m_oldRenderSurface = nullptr;
2675+
SAFE_RELEASE(m_newRenderSurface);
2676+
SAFE_RELEASE(m_renderTexture);
2677+
SAFE_RELEASE(m_oldRenderSurface);
2678+
SAFE_RELEASE(m_oldDepthSurface);
26762679
m_currentShader = ST_INVALID;
26772680
m_currentFilter = FT_NULL_FILTER;
26782681
//release any assets associated with a shader (vertex/pixel shaders, textures, etc.)
@@ -2831,9 +2834,20 @@ void W3DShaderManager::startRenderToTexture()
28312834

28322835
if (m_renderingToTexture || m_newRenderSurface==nullptr || m_oldDepthSurface==nullptr) return;
28332836
HRESULT hr = DX8Wrapper::_Get_D3D_Device8()->SetRenderTarget(m_newRenderSurface,m_oldDepthSurface);
2834-
DEBUG_ASSERTCRASH(hr==S_OK, ("Set target failed unexpectedly."));
2837+
2838+
// TheSuperHackers @bugfix If SetRenderTarget fails (e.g. due to MSAA forced by driver
2839+
// profile causing a depth buffer mismatch that D3DSURFACE_DESC doesn't report), permanently
2840+
// disable RTT to prevent repeated failures and accidental backbuffer clears.
28352841
if (hr != S_OK)
2842+
{
2843+
// Permanently disable RTT
2844+
SAFE_RELEASE(m_newRenderSurface);
2845+
SAFE_RELEASE(m_renderTexture);
2846+
SAFE_RELEASE(m_oldRenderSurface);
2847+
SAFE_RELEASE(m_oldDepthSurface);
28362848
return;
2849+
}
2850+
28372851
m_renderingToTexture = true;
28382852
if (TheGlobalData->m_showSoftWaterEdge)
28392853
{ //Soft water edges use frame buffer destination alpha so we must clear it to a known value.

Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DSmudge.cpp

Lines changed: 29 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ void W3DSmudgeManager::reset ()
6666

6767
void W3DSmudgeManager::ReleaseResources()
6868
{
69-
#ifdef USE_COPY_RECTS
7069
REF_PTR_RELEASE(m_backgroundTexture);
71-
#endif
7270
REF_PTR_RELEASE(m_indexBuffer);
7371
}
7472

@@ -85,9 +83,7 @@ void W3DSmudgeManager::ReAcquireResources()
8583
surface->Get_Description(surface_desc);
8684
REF_PTR_RELEASE(surface);
8785

88-
#ifdef USE_COPY_RECTS
89-
m_backgroundTexture = MSGNEW("TextureClass") TextureClass(TheTacticalView->getWidth(),TheTacticalView->getHeight(),surface_desc.Format,MIP_LEVELS_1,TextureClass::POOL_DEFAULT, true);
90-
#endif
86+
m_backgroundTexture = MSGNEW("TextureClass") TextureClass(surface_desc.Width,surface_desc.Height,surface_desc.Format,MIP_LEVELS_1,TextureClass::POOL_DEFAULT, true);
9187

9288
m_backBufferWidth = surface_desc.Width;
9389
m_backBufferHeight = surface_desc.Height;
@@ -207,15 +203,20 @@ Bool W3DSmudgeManager::testHardwareSupport()
207203
{ //we have not done the test yet.
208204

209205
IDirect3DTexture8 *backTexture=W3DShaderManager::getRenderTexture();
210-
if (!backTexture)
211-
{ //do trivial test first to see if render target exists.
206+
if (!backTexture || !W3DShaderManager::isRenderingToTexture())
207+
{
208+
// TheSuperHackers @bugfix When Render-To-Texture is disabled globally, we fallback
209+
// to copying the backbuffer to a texture.
210+
if (m_backgroundTexture)
211+
{
212+
m_hardwareSupportStatus = SMUDGE_SUPPORT_YES;
213+
return TRUE;
214+
}
215+
212216
m_hardwareSupportStatus = SMUDGE_SUPPORT_NO;
213217
return FALSE;
214218
}
215219

216-
if (!W3DShaderManager::isRenderingToTexture())
217-
return FALSE; //can't do the test unless we're rendering to texture.
218-
219220
VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
220221
DX8Wrapper::Set_Material(vmat);
221222
REF_PTR_RELEASE(vmat); //no need to keep a reference since it's a preset.
@@ -306,6 +307,22 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo)
306307
if (!testHardwareSupport())
307308
return;
308309

310+
SurfaceClass *backBuffer = DX8Wrapper::_Get_DX8_Back_Buffer();
311+
312+
if (!backBuffer)
313+
return;
314+
315+
SurfaceClass *background=m_backgroundTexture ? m_backgroundTexture->Get_Surface_Level() : nullptr;
316+
317+
if (!background)
318+
{
319+
REF_PTR_RELEASE(backBuffer);
320+
return;
321+
}
322+
323+
SurfaceClass::SurfaceDescription surface_desc;
324+
backBuffer->Get_Description(surface_desc);
325+
309326
CameraClass &camera=rinfo.Camera;
310327
Vector3 vsVert;
311328
Vector4 ssVert;
@@ -327,23 +344,6 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo)
327344
camera.Get_View_Matrix(&view);
328345
camera.Get_Projection_Matrix(&proj);
329346

330-
SurfaceClass::SurfaceDescription surface_desc;
331-
#ifdef USE_COPY_RECTS
332-
SurfaceClass *background=m_backgroundTexture->Get_Surface_Level();
333-
background->Get_Description(surface_desc);
334-
#else
335-
D3DSURFACE_DESC D3DDesc;
336-
337-
IDirect3DTexture8 *backTexture=W3DShaderManager::getRenderTexture();
338-
if (!backTexture || !W3DShaderManager::isRenderingToTexture())
339-
return; //this card doesn't support render targets.
340-
341-
backTexture->GetLevelDesc(0,&D3DDesc);
342-
343-
surface_desc.Width = D3DDesc.Width;
344-
surface_desc.Height = D3DDesc.Height;
345-
#endif
346-
347347
Real texClampX = (Real)TheTacticalView->getWidth()/(Real)surface_desc.Width;
348348
Real texClampY = (Real)TheTacticalView->getHeight()/(Real)surface_desc.Height;
349349

@@ -421,23 +421,16 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo)
421421

422422
if (!count)
423423
{
424-
#ifdef USE_COPY_RECTS
425424
REF_PTR_RELEASE(background);
426-
#endif
425+
REF_PTR_RELEASE(backBuffer);
427426
return; //nothing to render.
428427
}
429428

430-
#ifdef USE_COPY_RECTS
431-
SurfaceClass *backBuffer=DX8Wrapper::_Get_DX8_Back_Buffer();
432-
433-
backBuffer->Get_Description(surface_desc);
434-
435429
//Copy the area of backbuffer occupied by smudges into an alternate buffer.
436430
background->Copy(0,0,0,0,surface_desc.Width,surface_desc.Height,backBuffer);
437431

438432
REF_PTR_RELEASE(background);
439433
REF_PTR_RELEASE(backBuffer);
440-
#endif
441434

442435
Matrix4x4 identity(true);
443436
DX8Wrapper::Set_Transform(D3DTS_WORLD,identity);
@@ -447,18 +440,15 @@ void W3DSmudgeManager::render(RenderInfoClass &rinfo)
447440
//DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueSpriteShader);
448441

449442
DX8Wrapper::Set_Shader(ShaderClass::_PresetAlphaShader);
450-
#ifdef USE_COPY_RECTS
443+
451444
DX8Wrapper::Set_Texture(0,m_backgroundTexture);
452-
#else
453-
DX8Wrapper::Set_DX8_Texture(0,backTexture);
454445
//Need these states in case texture is non-power-of-2
455446
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP);
456447
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP);
457448
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ADDRESSW, D3DTADDRESS_CLAMP);
458449
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR);
459450
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
460451
DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_MIPFILTER, D3DTEXF_NONE);
461-
#endif
462452
VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
463453
DX8Wrapper::Set_Material(vmat);
464454
REF_PTR_RELEASE(vmat);

Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,6 @@ static ShaderClass blendStagesShader(SC_DETAIL_BLEND);
165165

166166
WaterRenderObjClass *TheWaterRenderObj=nullptr; ///<global water rendering object
167167

168-
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=nullptr; } }
169-
170168
void doSkyBoxSet(Bool startDraw)
171169
{
172170
if (TheWritableGlobalData)

Core/Libraries/Source/WWVegas/WWLib/WWCommon.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
#include "stringex.h"
2424
#include <Utility/stdio_adapter.h>
2525

26+
#ifndef SAFE_RELEASE
27+
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=nullptr; } }
28+
#endif
2629

2730
// This macro serves as a general way to determine the number of elements within an array.
2831
#ifndef ARRAY_SIZE

0 commit comments

Comments
 (0)