Skip to content

bugfix(rendering): Fix Microwave Heat Haze blackout on (Nvidia) forced AA#2374

Open
githubawn wants to merge 2 commits intoTheSuperHackers:mainfrom
githubawn:fix/nvidia-microwave-aa
Open

bugfix(rendering): Fix Microwave Heat Haze blackout on (Nvidia) forced AA#2374
githubawn wants to merge 2 commits intoTheSuperHackers:mainfrom
githubawn:fix/nvidia-microwave-aa

Conversation

@githubawn
Copy link

This PR aims to resolve the black screen bug caused by driver-forced MSAA, continuing and refining the work started in #1073.

The Bug: When users force MSAA via their driver control panel, the driver secretly upgrades the depth buffer to be multisampled. However, the Direct3D 8 API still reports MultiSampleType=NONE for created textures. When ScreenDefaultFilter attempts to use Render-To-Texture (RTT), it binds a non-MSAA texture to this secretly-MSAA depth buffer. This surface mismatch is a D3D API violation that silently breaks depth testing, resulting in a black screen.

This PR fixes the issue by permanently disabling the RTT path inside ScreenDefaultFilter::preRender (falling back to the CopyRects smudge path).

Co-authored-by: stm <14291421+stephanmeesters@users.noreply.github.com>
@greptile-apps
Copy link

greptile-apps bot commented Mar 1, 2026

Greptile Summary

Resolves black screen bug when MSAA is forced via Nvidia driver control panel by implementing a defensive multi-layered approach.

Key Changes:

  • Detects multisampled surfaces during shader manager initialization and prevents RTT resource creation
  • Disables RTT redirection in ScreenDefaultFilter::preRender() to prevent API violations
  • Adds graceful failure handling in startRenderToTexture() that permanently disables RTT on SetRenderTarget failure
  • Removes all USE_COPY_RECTS conditional compilation, making the Copy path always available
  • Fixes dimension mismatch in smudge system by using backbuffer dimensions instead of tactical view dimensions
  • Adds fallback logic in testHardwareSupport() to accept Copy path when RTT is unavailable

Technical Details:
When driver-forced MSAA is active, Direct3D 8 API incorrectly reports MultiSampleType=NONE while the depth buffer is actually multisampled. Binding a non-MSAA render target texture to this MSAA depth buffer violates D3D API contract and silently breaks depth testing. The fix prevents this mismatch by detecting MSAA and falling back to the CopyRects path, which properly resolves MSAA surfaces when dimensions match exactly.

Confidence Score: 5/5

  • This PR is safe to merge with high confidence - implements defensive programming with multiple fallback layers
  • The implementation uses defensive multi-layered detection (init-time, SetRenderTarget-time, and filter-level), has proper resource management with correct Release/null patterns, preserves existing behavior for non-MSAA cases, and includes comprehensive comments explaining the D3D8 API violation and solution. The dimension fix correctly addresses the CopyRects requirement for matching surface sizes.
  • No files require special attention - all changes are well-structured and defensive

Important Files Changed

Filename Overview
Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DSmudge.h Removed conditional compilation guards around m_backgroundTexture, making it unconditionally available for the Copy path fallback
Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp Implements MSAA detection and RTT disabling: detects multisampled surfaces during init, prevents RTT on forced MSAA, adds graceful failure handling
Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DSmudge.cpp Removes conditional compilation, fixes dimension mismatch by using backbuffer dimensions, adds Copy path fallback support when RTT is unavailable

Last reviewed commit: 6533d57

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +2850 to +2853
if (m_newRenderSurface) { m_newRenderSurface->Release(); m_newRenderSurface = nullptr; }
if (m_renderTexture) { m_renderTexture->Release(); m_renderTexture = nullptr; }
if (m_oldRenderSurface) { m_oldRenderSurface->Release(); m_oldRenderSurface = nullptr; }
if (m_oldDepthSurface) { m_oldDepthSurface->Release(); m_oldDepthSurface = nullptr; }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple statements on same line as if condition prevents setting individual breakpoints

Suggested change
if (m_newRenderSurface) { m_newRenderSurface->Release(); m_newRenderSurface = nullptr; }
if (m_renderTexture) { m_renderTexture->Release(); m_renderTexture = nullptr; }
if (m_oldRenderSurface) { m_oldRenderSurface->Release(); m_oldRenderSurface = nullptr; }
if (m_oldDepthSurface) { m_oldDepthSurface->Release(); m_oldDepthSurface = nullptr; }
if (m_newRenderSurface)
{
m_newRenderSurface->Release();
m_newRenderSurface = nullptr;
}
if (m_renderTexture)
{
m_renderTexture->Release();
m_renderTexture = nullptr;
}
if (m_oldRenderSurface)
{
m_oldRenderSurface->Release();
m_oldRenderSurface = nullptr;
}
if (m_oldDepthSurface)
{
m_oldDepthSurface->Release();
m_oldDepthSurface = nullptr;
}

Context Used: Rule from dashboard - Always place if/else/for/while statement bodies on separate lines from the condition to allow precis... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp
Line: 2850-2853

Comment:
Multiple statements on same line as `if` condition prevents setting individual breakpoints

```suggestion
		if (m_newRenderSurface)
		{
			m_newRenderSurface->Release();
			m_newRenderSurface = nullptr;
		}
		if (m_renderTexture)
		{
			m_renderTexture->Release();
			m_renderTexture = nullptr;
		}
		if (m_oldRenderSurface)
		{
			m_oldRenderSurface->Release();
			m_oldRenderSurface = nullptr;
		}
		if (m_oldDepthSurface)
		{
			m_oldDepthSurface->Release();
			m_oldDepthSurface = nullptr;
		}
```

**Context Used:** Rule from `dashboard` - Always place if/else/for/while statement bodies on separate lines from the condition to allow precis... ([source](https://app.greptile.com/review/custom-context?memory=16b9b669-b823-49be-ba5b-2bd30ff3ba6d))

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@stephanmeesters
Copy link

Maybe we can accurately tell if MSAA was forced with some of the changes in #1073 like below, and use that in place of desc.MultiSampleType

static D3DFORMAT _Get_D3D_Back_Buffer_Format() { return DisplayFormat; }
...
WWINLINE unsigned int DX8Wrapper::Bytes_Per_Pixel(D3DFORMAT format)
{
	switch (format)
	{
	// 8-bit formats
	..
	// Depth / stencil
	case D3DFMT_D16_LOCKABLE:
	case D3DFMT_D16:
	case D3DFMT_D15S1:
	case D3DFMT_D24S8:
	case D3DFMT_D24X8:
	case D3DFMT_D24X4S4:
	case D3DFMT_D32:
		return 0;
		...
}

Do you know if the RTT path is much faster when MSAA is off compared to copyRects? Is it worth the extra complexity to support both?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants