MSAA? Does it work? How to make it work?

Basically title. I looked through the forums with the search function and I mostly found people saying it’s not working right now?

If it does work (on DirectX that is) how do i make it work?
Thanks in advance :slightly_smiling:

Obviously temporal antialiasing is interesting as it is very challenging to do well, but I think a simple MSAA solution would be nice as well and it should in theory be easy to set up.

Am using forward rendering, no deferred stuff (yet?)

EDIT: Yes i am using graphics.PreferMultiSampling = true; as well

Currently only works for OpenGL AFAIK, doesn’t work for me either on DirectX https://github.com/mono/MonoGame/issues/358

It should work for the backbuffer just fine… at least the code for setting up the back buffer with multisampling is all there.

The code for enabling multisampling on a render target is there too:

https://github.com/mono/MonoGame/blob/develop/MonoGame.Framework/Graphics/RenderTarget2D.DirectX.cs#L60

So i’m not sure why exactly it isn’t working in your case.

Added an issue for it for the 3.6 release in the mean time to remind us to address it: https://github.com/mono/MonoGame/issues/4734

Maybe a mistake on my part, i will research further

To add to the issue something i forgot:

                An unhandled exception of type 'SharpDX.SharpDXException' occurred in SharpDX.dll

                Additional information: HRESULT: [0x80070057], Module: [General], ApiCode: [E_INVALIDARG/Invalid Arguments], Message: The parameter is incorrect.

The parameter being:

        _renderTarget1 = new RenderTarget2D(_graphicsDevice,
                        (int) (width * GameSettings.SuperSample),
                        (int) (height*GameSettings.SuperSample),
                        false,
                        _graphicsDevice.PresentationParameters.BackBufferFormat,
                        DepthFormat.Depth24, 4, RenderTargetUsage.PlatformContents);

4 - which is declared as int MultisampleCount

If i set it to zero it will work.

Now if I set the DepthFormat.DepthNone it works as well (which it obviously should as Tom posted in the code snippet). And obviously without Depth MSAA can’t work, but no depth is no option anyways

Interesting… the only thing I can think of is that somehow we’re initializing the MSAA incorrectly or we’re using a setting that isn’t supported on your hardware.

If you go up to 6 or 8 does it work?

Same error here, tried 2, 4, 6 and 8.

I’ll give this a test here shortly and see what I find.

So back buffer MSAA was indeed broken in the latest develop code. I’m working on the fix plus a unit test now.

FYI. The start of MSAA fixes under DirectX…

There is still more work to do here, but it is a start.

Wow great! I’m sure this will be helpful to a lot of people <3

I’ll try it out when I’m back from work

The development build is automatically always the newest right? So I don’t need to compile it myself, right?

This is the framework code that gives the exception:

 // Create the view for binding to the device.
                _depthStencilView = new DepthStencilView(GraphicsDevice._d3dDevice, depthBuffer,
                    new DepthStencilViewDescription()
                    {
                        Format = SharpDXHelper.ToFormat(DepthStencilFormat),
                        Dimension = DepthStencilViewDimension.Texture2D
                    });

If I change the code to this:

  DepthStencilViewDimension dsvDimension;
            if (MultiSampleCount > 1)
            {
                dsvDimension = DepthStencilViewDimension.Texture2DMultisampled;
            }
            else
            {
                dsvDimension = DepthStencilViewDimension.Texture2D;
            }

            DepthStencilViewDescription desc = new DepthStencilViewDescription()
                {
                    Format = SharpDXHelper.ToFormat(DepthStencilFormat),
                    Dimension = dsvDimension          
                };

there is no exception, but rendering seems to output a black surface…

Found this information, not sure if it’s relevant?

In case you render to texture with multisampling, you also need to resolve your resource, multi sampled textures are bound as Texture2DMS (instead of Texture2D) in shaders.

To do so, you need to create a second texture (with same format/size), but with only one sample.

Then once you’re done rendering your multisampled texture, you need to do the following call:

deviceContext.ResolveSubresource(multisampledtexture, 0, nonmultisampledtexture,
0, format);

This 3 year old issue mentions this, but development is stalled because of platform issues it seems:

I added this code to the framework to be able to resolve the multisampled rendertarget to a normal rendertarget:

public void ResolveSubresource(RenderTarget2D destination) 
        {
            GraphicsDevice._d3dContext.ResolveSubresource(this._texture, 0, destination._texture, 0, 
                SharpDXHelper.ToFormat(_format)); // SharpDX.DXGI.Format.)
           
        }

It works, but unfortunately, both textures are blank. For some reason rendering to the MS render target ends up all white.

I got this error from RenderDoc:
"“Invalid output merger - Depth target is different size or MS count to render target(s)”
Apparently the depth buffer is wrong in some way.

Apparently, the texture inside the RenderTarget is created without multisampling. This is the code:

 internal override SharpDX.Direct3D11.Resource CreateTexture()
		{
            // TODO: Move this to SetData() if we want to make Immutable textures!
            var desc = new SharpDX.Direct3D11.Texture2DDescription();
            desc.Width = width;
            desc.Height = height;
            desc.MipLevels = _levelCount;
            desc.ArraySize = ArraySize;
            desc.Format = SharpDXHelper.ToFormat(_format);
            desc.BindFlags = SharpDX.Direct3D11.BindFlags.ShaderResource;
            desc.CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.None;
            desc.SampleDescription.Count = 1;
            desc.SampleDescription.Quality = 0;
            desc.Usage = SharpDX.Direct3D11.ResourceUsage.Default;
            desc.OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.None;

            if (_renderTarget)
            {
                desc.BindFlags |= SharpDX.Direct3D11.BindFlags.RenderTarget;
                if (_mipmap)
                {
                    // Note: XNA 4 does not have a method Texture.GenerateMipMaps() 
                    // because generation of mipmaps is not supported on the Xbox 360.
                    // TODO: New method Texture.GenerateMipMaps() required.
                    desc.OptionFlags |= SharpDX.Direct3D11.ResourceOptionFlags.GenerateMipMaps;
                }
            }
            if (_shared)
                desc.OptionFlags |= SharpDX.Direct3D11.ResourceOptionFlags.Shared;

            return new SharpDX.Direct3D11.Texture2D(GraphicsDevice._d3dDevice, desc);
        }

public int MultiSampleCount { get; private set; }

is a property of RenderTarget. It looks like it should be property of the base class Texture2D instead, since the texture needs it to initialize itself. Of course, I only know about DirectX, not the other platforms.

With these changes, I got it working.

I found this when I was fixing the MSAA on the back buffer. It requires a larger amount of refactoring to fix the render targets.

Well, I think it should be prioritized higher, since not having it means a visual degradation from XNA. All the fancy DX 12 stuff can come later. MSAA is a 10-year old technology, it really isn’t good that MonoGame doesn’t support it.

hey, sorry to necrobump this thread.

I’m trying myself to get MSAA to work for RTs but I can’t properly get it to work.

Can you or someone else share how you got it to work?

I’ve changed the RenderTargets to have proper sampleDescription / quality (not sure about that one) and have that not crash on me any more, but I don’t have a real clue how MSAA resolve works. Can someone help me or guide me?

I understand I need to resolve the multisampled texture to a non-msaa’d texture to use it, but where does the shader access the texture / where do i need to make the switch?

EDIT: Nevermind i got it. I’ll post a short guide soon

EDIT2: Quick Overview: How to work with MSAA (DirectX too!)