Jump to content
  • Advertisement
lubbe75

DX12 MSAA in DX12?

Recommended Posts

Does anyone have a working example of how to implement MSAA in DX12? I have read short descriptions and I have seen code fragments on how to do it with DirectX Tool Kit.

I get the idea, but with all the pipeline states, root descriptions etc I somehow get lost on the way.

Could someone help me with a link pointing to a small implementation in DirectX 12 (or SharpDX with DX12)?

 

Share this post


Link to post
Share on other sites
Advertisement

I have made it, and it's actually not that hard

  1. Create a pipeline state for render target with specific MSAA samples and quality, like this (I've removed additional code)
     
    DXGI_SAMPLE_DESC samplerDesc;
    samplerDesc.Count = samplesMSAA;
    samplerDesc.Quality = qualityMSAA;
    
    D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = { 0 };
    ...
    desc.SampleDesc = samplerDesc;
    
    device->CreateGraphicsPipelineState(&desc, __uuidof(ID3D12PipelineState), (void**)&pipelineState);
  2. Create render target buffers that hold rendered data (for both - color & depth buffers)
     
    	D3D12_RESOURCE_DESC desc = DescTex2D(...)
    	desc.SampleDesc.Count = samplesMSAA;
    	desc.SampleDesc.Quality = qualityMSAA;
    
     	....
    
    	CreateTextureResource(...)
    	CreateDerivedViews(...)
  3. Next you need to have pipeline state for resolving and I assume you want to resolve into backbuffer for swap chain (so you already have color (& depth) buffers for that). This pipeline state and texture buffers are no-MSAA, so samples count is 1 and sample quality is 0
     
  4. Rendering is then straight forward - you render your scene with MSAA pipeline state into MSAA buffers. And during resolve you attach SRV of those buffers and resolve in your shader like for example this (note SamplesMSAA is a define with number of samples used in MSAA):
     
    Texture2DMS<float4, SamplesMSAA> msaaTexture : register(t0);
      
    cbuffer msaaDesc : register(b0)
    {
    	uint2 dimensions;
    }
      
    struct Input
    {
    	float4 position : SV_POSITION;
    	float2 texCoord : TEXCOORD0;
    };
    
    Input VS(uint id : SV_VertexID, 
    	float3 position : POSITION,
    	float2 texCoord : TEXCOORD0)
    {
    	Input result;
    
    	result.position = float4(position, 1.0f);
    	result.texCoord = texCoord;
    
    	return result;
    }
    
    float4 PS(Input input)
    {
    	uint2 coord = uint2(input.texCoord.x * dimensions.x, input.texCoord.y * dimensions.y);
    	
    	float4 tex = float4(0.0f, 0.0f, 0.0f, 0.0f);
      
    #if SamplesMSAA == 1
    	tex = diffuse.Load(coord, 0);
    #else
    	for (uint i = 0; i < SamplesMSAA; i++)
    	{
    		tex += diffuse.Load(coord, i);
    	}
    	tex *= 1.0f / SamplesMSAA;
    #endif
    		
    	return tex;
    }

     

I could post working code somewhere, but I have most objects in DX12 wrapped, and whole engine attached to it - so it would probably make no sense and would be overly confusing (my most simple example does MSAA with deferred shading and post-tonemapping resolve... along with voxel cone tracing - that is a LOT of noise around).

Share this post


Link to post
Share on other sites
3 hours ago, Vilem Otte said:

I have made it, and it's actually not that hard

Thanks for the encouragement.

I guess I need even more details (that's where the devil is). Following your example I am at creating another pipeline state, more buffers, shaders etc, but so far I haven't gotten all the parameters right. There is always another clash of illegal parameter combinations it seems. For instance, how do you match 

Texture2DMS<float4, SamplesMSAA> msaaTexture : register(t0);

with an input structure? And how does the corresponding shader resource view description look like? Do I need to create new resource heaps for the new render target and depth targets (I guess adding to the already existing heaps is fine)? What parameters do you give when creating your resource descriptions?

Maybe you are not so keen on reading DX12 + SharpDX code, but if you are, here is an interesting example I found where they render to an off-screen buffer (for post processing effects). I understand the code, and it's working, but they don't do MSAA. Can you or someone else help me to figure out what would be needed in order to add multisampling here? I have a feeling it's not much missing.

https://github.com/RobyDX/SharpDX_D3D12HelloWorld/blob/master/D3D12HelloRenderTarget/HelloRenderTarget.cs

Edited by lubbe75
Forgot to add the link

Share this post


Link to post
Share on other sites

Yes, you will need additional: pipeline state (therefore shaders and most likely root signature) and buffers (color and depth).

As for matching msaaTexture - I have a root signature with 1 descriptor table there, that contains 1 descriptor range. This range contains just 1 descriptor of type D3D12_DESCRIPTOR_RANGE_TYPE_SRV.

This SRV is created standardly with CreateShaderResourceView. The resource passed in is committed resource for color buffer. I might read the code later (I just briefly went through - and it doesn't contain additional pipeline state, buffers, etc. yet) - as right now I'm just on short lunch brake in work.

Share this post


Link to post
Share on other sites

ResolveSubresource and ResolveSubresouceRegion (new to DX12) still exist if you don't want to do your MSAA resolve manually. If your resolve operation is just an average of the N samples then using the Resolve API will be at least as fast as doing it yourself.

Share this post


Link to post
Share on other sites
16 hours ago, Vilem Otte said:

 it doesn't contain additional pipeline state, buffers, etc. yet

Actually it does. Almost everything is set up in the LoadRenderTargetData function. Compare it with the non-post-processing version in https://github.com/RobyDX/SharpDX_D3D12HelloWorld/blob/master/D3D12HelloMesh/HelloMesh.cs it's clear what has been added. 

Anyway, I'll continue trying today. Finding more than just code fragments for MSAA in Dx12 seems impossible.

ajmiles, thanks for the tip. I will use it when I get that far.

Share this post


Link to post
Share on other sites

Ok, got it!

Going the ResolveSubresource way was really a lot easier. It's good enough for what I am looking for. With this method there is no need to have extra pipeline states, root signatures or shaders. Just the extra render target and depth targets will do.

Thanks Vilem Otte and ajmiles for standing by!

 

Share this post


Link to post
Share on other sites

Oh, forgot to ask a question...

How do I switch MSAA on / off at run-time? The thing is that when I want MSAA I need to specify sample description count > 1 already when creating the pipeline state object. This number cannot be changed later on, can it?

Is the only solution to create another pipeline state object (with its own command lists etc) and then switch between these two sets at run-time?

Share this post


Link to post
Share on other sites

You don't need additional command lists, etc. A pipeline state is enough.

You can create 2 pipeline states and in the code use:

ID3D12GraphicsCommandList::SetPipelineState(ID3D12PipelineState* pPipelineState)

 

In a way that:

if (msaa)
{
    cmdList.SetPipelineState(msaaPSO);
    ... 
}
else
{
    cmdList.SetPipelineState(nonMsaaPSO);
    ...
}

...

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!