MSAA in DirectX 11

by on under Graphics
4 minute read

If you just need to read what i’ve done to fix MSAA go into LoST section.

Story

One day one of my friends send me a message with a two simple sentances:

Why your screenshots so jittery and aliased? Fix it!

Without any arguing that i was lazy for that i chose MSAA for my main AA alghorithm. I Thought that it would be easy to implement it! Just add some checks, change some things here add some code here and should be working!

Right?

Wrong!

When i started digging i saw how many things must be done in order to enable and use MSAA. I’ll skip a whole story about how i rage each time when i fail to make MSAA work, so bear with me.

Last day i was reading an article written by Turanszkij and i saw a link to his discord server.

This guy helped me a lot and saved a lot of time for future me. Lv ya

In case you barly see image or can barely read what he wrote:

@SweetLuna Check the debug layer if it outputs anything when you render to MSAA texture. Also check that you have set a proper sample mask with OMSetBlendState that allows all samples to be written

So thanks to him i finally made MSAA work.

Results

Without MSAA No MSAA

MSAA x8 With MSAA

Close look at bridge without MSAA No MSAA

MSAA x8 With MSAA

LoST for MSAA

List of several things that i encountered with when i tried integrating MSAA into my own engine.

  1. Check if current device/hardware/software can handle MSAA for this exact DXGI_FORMAT.
    • If yes, then what is max level?
    • If returned Quality > 0 and SampleCount > 1
      • This device/hardware/software supports MSAA for this format with SampleCount levels.

The way how i check for MSAA support can be found here and here.

  1. Each RTV that has type of Texture2DMS must have exact RTV but with type of Texture2D.
  2. For DSV that has SampleCount > 1 must have:
    • Must have same DSV with No MSAA and No UAV.
    • Must have same DSV with No MSAA, W/ UAV, and without DSV/RTV.
  3. Enable MSAA in RasterState.
    MultisampleEnable = true;
    
  4. Set Sample Mask for BlendState to 0xFFFFFFFF.

    Mine was always set to 1, and i always wondered why only 1st sample had data, when rest of them - don’t?

  5. For each RTV MSAA reolve is simple. Just call
    ID3D11DeviceContext::ResolveSubresource(ID3D11Resource *Dest, UINT DestSubres, 
                                         ID3D11Resource *Src, UINT SrcSubres, 
                                         DXGI_FORMAT format);
    
  6. For depth you do this by hand. I use similar technique as described by Turanszkij for WikedEngine.
    • Bind no MSAA depth buffer (the one with UAV) to UAV slot for compute shader.
    • Bind original depth buffer with MSAA to SRV slot.
    • Dispatch * Shader can be found here * Depth MSAA resolving function in my RenderTarget class can be found here
  7. Add SV_SampleIndex for input into rendering shader.
    GBuffer main(PS In, bool bIsFront : SV_IsFrontFace, uint SampleIndex : SV_SampleIndex) {
    
  8. Replace in every shader where you sample original SRV (with MSAA) Texture2D with Texture2DMS.
  9. Store for each RTV and DSV(for 3rd one you don’t need this) created their SampleCount.

References

MSAA, HLSL, DirectX, DirectX 11