Sign in to follow this  
cozzie

Changing MSAA settings on the fly

Recommended Posts

Hi all,
Just a short question on MSAA in D3D11.

I've got it all working fine, when I setup MSAA directly through initialization.
Now I want to create a function to change, either enable/disable or change the number of samples, realtime.

From what I could find out so far, I just need to recreate the swapchain (through the DXGI factory), and be done.
But when I look in my code, I see that my depthstencil texture also has some MSAA related properties. Does that mean I'd also have to recreate that? (tex + resource view)
 
Here's my code, which is executed initially (SwapChain creation):
 
	// Fill out the DXGI_SWAP_CHAIN_DESC
	DXGI_SWAP_CHAIN_DESC sd;
	sd.BufferDesc.Width  = mSettings.GetScreenWidth();
	sd.BufferDesc.Height = mSettings.GetScreenHeight();
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
	sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

	// Use MSAA? 
	if(mSettings.GetMSAAEnabled())
	{
		sd.SampleDesc.Count = mSettings.GetMSAANrSamples();
		if(mMSAAQuality == 0) sd.SampleDesc.Quality = D3D11_STANDARD_MULTISAMPLE_PATTERN;
		else sd.SampleDesc.Quality = mMSAAQuality-1;
		// NOTE: RASTERIZER STATE DETERMINES QUADRILATERAL VS ALPHA-LINE AA
		// https://msdn.microsoft.com/en-us/library/windows/desktop/ff476198(v=vs.85).aspx
	}
	// No MSAA
	else
	{
		sd.SampleDesc.Count   = 1;
		sd.SampleDesc.Quality = 0;
	}

	sd.BufferUsage  = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.BufferCount  = 1;
	sd.OutputWindow = pHwnd;
	
	if(mSettings.GetWindowed()) sd.Windowed = true;
		else sd.Windowed = false;

	sd.SwapEffect   = DXGI_SWAP_EFFECT_DISCARD;
	sd.Flags        = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

	// create swap chain using same IDXGIFactory as used to create device
	IDXGIDevice *dxgiDevice = 0;
	if(FAILED(mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice))) return false;

	IDXGIAdapter *dxgiAdapter = 0;
	if(FAILED(dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dxgiAdapter))) return false;

	IDXGIFactory *dxgiFactory = 0;
	if(FAILED(dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory))) return false;

	if(FAILED(dxgiFactory->CreateSwapChain(mDevice, &sd, &mSwapChain))) return false;

And when resizing the window or changing the resolution (DepthStencil tex and view):

	// Create the depth/stencil buffer and view.
	D3D11_TEXTURE2D_DESC depthStencilDesc;
	
	depthStencilDesc.Width     = mSettings.GetScreenWidth();
	depthStencilDesc.Height    = mSettings.GetScreenHeight();
	depthStencilDesc.MipLevels = 1;
	depthStencilDesc.ArraySize = 1;
	depthStencilDesc.Format    = DXGI_FORMAT_D24_UNORM_S8_UINT;
	       
	// Use MSAA? --must match swap chain MSAA values.
	if(mSettings.GetMSAAEnabled())
	{
		depthStencilDesc.SampleDesc.Count = mSettings.GetMSAANrSamples();

		if(mMSAAQuality == 0) depthStencilDesc.SampleDesc.Quality = D3D11_STANDARD_MULTISAMPLE_PATTERN;
		else depthStencilDesc.SampleDesc.Quality = mMSAAQuality-1;
	}
	// No MSAA
	else
	{
		depthStencilDesc.SampleDesc.Count   = 1;
		depthStencilDesc.SampleDesc.Quality = 0;
	}

	depthStencilDesc.Usage          = D3D11_USAGE_DEFAULT;
	depthStencilDesc.BindFlags      = D3D11_BIND_DEPTH_STENCIL;
	depthStencilDesc.CPUAccessFlags = 0; 
	depthStencilDesc.MiscFlags      = 0;

	hr = mDevice->CreateTexture2D(&depthStencilDesc, 0, &mDepthStencilBuffer);
	if(FAILED(hr)) return false;

	hr = mDevice->CreateDepthStencilView(mDepthStencilBuffer, 0, &mDepthStencilView);
	if(FAILED(hr)) return false;

	// Bind the render target view and depth/stencil view to the pipeline.
	mImmediateContext->OMSetRenderTargets(1, &mRenderTargetView, mDepthStencilView);

Any input on what to do here is appreciated.

My assumption would be that both are needed, but just want to be sure (because in other topics I've just read about the SwapChain).
?If both are needed, then it's quite simple; just add a call to OnResize after I've created the new SwapChain.

Share this post


Link to post
Share on other sites

To perform MSAA rendering, the render target and the depth buffer have to match in the number of samples and quality, so the short answer is yes, you have to recreate it too.

 

For the longer answer : You should not use MSAA swap chain. You should create a regular swap chain, and create the MSAA surfaces you want separately and resolve into your backbuffer when you need it. As a side note, MSAA swap chain are even deprecated and creation fail right now with DirectX12, and even with DirectX11 if you are using UWP.

Share this post


Link to post
Share on other sites

Thanks, that clears things up.

Just to make sure I understand it, in pseudo code I'd be doing the following:

 

Initially:

- create device

- create swapchain without MSAA

- create depthstencil texture and view with MSAA

- create rendertarget (tex and view) with MSAA

- set rendertarget

- render nice stuff using MSAA :)

 

When changing MSAA settings:

- recreate depthstencil like above

- recreate rendertarget like above

- set updated rendertarget

- render nice stuff with other MSAA settings

 

Is this correct?

If so, do I 'enable'/ setup MSAA on a RT the same as with the SwapChain? (through it's desc parameters)

Share this post


Link to post
Share on other sites

 

its been answered, for some reason the thread didnt show up.  Deleting answer!


What do you mean?
I don't think I see the answer/ your reply (to the last question)

 

I mean, I basically wrote the answer your query as per galop1n answered.  For some reason, thread didn't show.  Didn't want to repeat :)

Share this post


Link to post
Share on other sites

I've been playing around and think I'm doing things the right way.

But.. the result is a black screen; when I debug through RenderDoc I see that the slot 0 RT is called "Texture2D RTV6".

When I 'do MSAA' directly through the SWAPCHAIN and don't use a RT with MSAA expliticitly, then the slot 0 RT is called "Serialized swap chain buffer".

Another conclusion is that 'RTV6' RT in RenderDoc shows the expected output. It's just not 'outputted' through the SwapChain I think.

 

I have understood in an other topic that the ResolveSubResource whould be done after drawing, but I also tried it after creating the RT directly (only when resizing or changing MSAA settings).

Any idea what might be wrong?

 

Ane addition; when I try to change MSAA settings of the RT 'on the fly', I get an error the the retrieved backBuffer has 0 samples set and the RT target has 4 (as expected).

Somehow the backbuffer isn't 'updated'.

 

Here's the code:

// initial creation of SwapChain
bool CD3d11App::CreateSwapChain()
{
	// Fill out a DXGI_SWAP_CHAIN_DESC to describe our swap chain.
	DXGI_SWAP_CHAIN_DESC sd;
	sd.BufferDesc.Width  = mClientWidth;
	sd.BufferDesc.Height = mClientHeight;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
	sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

	// NO MSAA - DONE THROUGH RENDER TARGET
	sd.SampleDesc.Count   = 1;
	sd.SampleDesc.Quality = 0;

	sd.BufferUsage  = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.BufferCount  = 1;
	sd.OutputWindow = mhMainWnd;
	sd.Windowed     = true;
	sd.SwapEffect   = DXGI_SWAP_EFFECT_DISCARD;
	sd.Flags        = 0;

	// To correctly create the swap chain, we must use the IDXGIFactory that was used to create the device. 

	IDXGIDevice* dxgiDevice = 0;
	HR(md3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice));
	      
	IDXGIAdapter* dxgiAdapter = 0;
	HR(dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dxgiAdapter));

	IDXGIFactory* dxgiFactory = 0;
	HR(dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory));

	if(mSwapChain) ReleaseCOM(mSwapChain);
	HR(dxgiFactory->CreateSwapChain(md3dDevice, &sd, &mSwapChain));
	
	ReleaseCOM(dxgiDevice);
	ReleaseCOM(dxgiAdapter);
	ReleaseCOM(dxgiFactory);

	return true;
}

// OnResize function, where I (re)create the RT
bool CD3d11App::OnResize()
{
	assert(md3dImmediateContext);
	assert(md3dDevice);
	assert(mSwapChain);

	ReleaseCOM(mRenderTargetView);
	ReleaseCOM(mDepthStencilView);
	ReleaseCOM(mDepthStencilBuffer);

	// Resize the swap chain 
	if(FAILED(mSwapChain->ResizeBuffers(1, mClientWidth, mClientHeight, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, 0))) return false;
	
	/***  TESTING: MANUAL RenderTarget view with MSAA or not ***/
	D3D11_TEXTURE2D_DESC renderTargetTexDesc;

	renderTargetTexDesc.Width				= mClientWidth;
	renderTargetTexDesc.Height				= mClientHeight;
	renderTargetTexDesc.MipLevels			= 1;
	renderTargetTexDesc.ArraySize			= 1;
	renderTargetTexDesc.Format				= DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
	renderTargetTexDesc.Usage				= D3D11_USAGE_DEFAULT;
	renderTargetTexDesc.BindFlags			= D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
	renderTargetTexDesc.CPUAccessFlags		= 0; 
	renderTargetTexDesc.MiscFlags			= 0;

	// MSAA part:
	renderTargetTexDesc.SampleDesc.Count	= 1;  
	renderTargetTexDesc.SampleDesc.Quality	= 0;  

	if(mEnableMSAA)
	{
		renderTargetTexDesc.SampleDesc.Count   = mMSAASamples;
		renderTargetTexDesc.SampleDesc.Quality = m4xMsaaQuality-1;
	}

	if(mRenderTargetTex) ReleaseCOM(mRenderTargetTex);
	if(FAILED(md3dDevice->CreateTexture2D(&renderTargetTexDesc, 0, &mRenderTargetTex))) return false;

	if(FAILED(md3dDevice->CreateRenderTargetView(mRenderTargetTex, 0, &mRenderTargetView))) return false;


// render function
void MainApp::DrawScene()
{
	float color[4] = { 0.3f, 0.3f, 0.3f, 1.0f };
	md3dImmediateContext->ClearRenderTargetView(mRenderTargetView, color);
	md3dImmediateContext->ClearDepthStencilView(mDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

	ID3D11Buffer *vsBuffers[1] = { mCBuffers[1].GetCBufferPtr() };
	md3dImmediateContext->VSSetConstantBuffers(1, 1, vsBuffers);

	ID3D11Buffer *psBuffers[2] = { mCBuffers[0].GetCBufferPtr(), mCBuffers[1].GetCBufferPtr() };
	md3dImmediateContext->PSSetConstantBuffers(0, 2, psBuffers);

	md3dImmediateContext->PSSetSamplers(0, 1, &mSamplerStates[currSamplerState]);

	md3dImmediateContext->DrawIndexed(mBoxIndexCount, mBoxIndexOffset, mBoxVertexOffset);

	// drawing done 
	ID3D11Texture2D* backBuffer;
	HR(mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBuffer)));
	md3dImmediateContext->ResolveSubresource(mRenderTargetTex, 0, backBuffer, 0, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB);
	ReleaseCOM(backBuffer);
	
	mSwapChain->Present(0, 0);
}

Edited by cozzie

Share this post


Link to post
Share on other sites

Thanks.

With the debug layer on, including info, I get only this (no errors or warnings):

'Minimal application.exe' (Win32): Loaded 'C:\Windows\SysWOW64\d3d11_3SDKLayers.dll'. Cannot find or open the PDB file.
D3D11 INFO: Create ID3D11Context: Name="unnamed", Addr=0x01181508, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097225: CREATE_CONTEXT]
D3D11 INFO: Create ID3DDeviceContextState: Name="unnamed", Addr=0x0482FC88, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #3145735: CREATE_DEVICECONTEXTSTATE]
D3D11 INFO: Create ID3D11BlendState: Name="unnamed", Addr=0x04832B7C, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097270: CREATE_BLENDSTATE]
D3D11 INFO: Create ID3D11DepthStencilState: Name="unnamed", Addr=0x02A00C1C, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097273: CREATE_DEPTHSTENCILSTATE]
D3D11 INFO: Create ID3D11RasterizerState: Name="unnamed", Addr=0x02A00DC4, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097276: CREATE_RASTERIZERSTATE]
D3D11 INFO: Create ID3D11Sampler: Name="unnamed", Addr=0x02A00F74, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097267: CREATE_SAMPLER]
D3D11 INFO: Create ID3D11Query: Name="unnamed", Addr=0x02A0111C, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097279: CREATE_QUERY]
IGIESW e:\projects\d3d11 practice\minimal application\debug\minimal application.exe found in whitelist: NOIGIWHW Game e:\projects\d3d11 practice\minimal application\debug\minimal application.exe found in whitelist: NOD3D11 INFO: Create ID3D11Texture2D: Name="unnamed", Addr=0x02A01B34, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097234: CREATE_TEXTURE2D]
D3D11 INFO: Destroy ID3D11Texture2D: Name="unnamed", Addr=0x02A01B34 [ STATE_CREATION INFO #2097236: DESTROY_TEXTURE2D]
D3D11 INFO: Create ID3D11Texture2D: Name="unnamed", Addr=0x02A01B34, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097234: CREATE_TEXTURE2D]
D3D11 INFO: Create ID3D11Texture2D: Name="unnamed", Addr=0x029EA48C, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097234: CREATE_TEXTURE2D]
D3D11 INFO: Create ID3D11RenderTargetView: Name="unnamed", Addr=0x019D372C, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097243: CREATE_RENDERTARGETVIEW]
D3D11 INFO: Create ID3D11Texture2D: Name="unnamed", Addr=0x029EAD4C, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097234: CREATE_TEXTURE2D]
D3D11 INFO: Create ID3D11DepthStencilView: Name="unnamed", Addr=0x0296A37C, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097246: CREATE_DEPTHSTENCILVIEW]
'Minimal application.exe' (Win32): Loaded 'C:\Windows\SysWOW64\rsaenh.dll'. Cannot find or open the PDB file.
D3D11 INFO: Create ID3D11VertexShader: Name="unnamed", Addr=0x019D4144, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097249: CREATE_VERTEXSHADER]
D3D11 INFO: Create ID3D11InputLayout: Name="unnamed", Addr=0x019D4414, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097264: CREATE_INPUTLAYOUT]
D3D11 INFO: Create ID3D11PixelShader: Name="unnamed", Addr=0x019E12E4, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097261: CREATE_PIXELSHADER]
D3D11 INFO: Create ID3D11Buffer: Name="unnamed", Addr=0x019DAB84, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097228: CREATE_BUFFER]
D3D11 INFO: Create ID3D11Buffer: Name="unnamed", Addr=0x019DB434, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097228: CREATE_BUFFER]
D3D11 INFO: Create ID3D11Sampler: Name="unnamed", Addr=0x019D7314, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097267: CREATE_SAMPLER]
D3D11 INFO: Create ID3D11Sampler: Name="unnamed", Addr=0x019D76DC, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097267: CREATE_SAMPLER]
D3D11 INFO: Create ID3D11Texture2D: Name="unnamed", Addr=0x019DD074, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097234: CREATE_TEXTURE2D]
D3D11 INFO: Create ID3D11ShaderResourceView: Name="unnamed", Addr=0x019DD38C, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097240: CREATE_SHADERRESOURCEVIEW]
D3D11 INFO: Create ID3D11Buffer: Name="unnamed", Addr=0x028E6AE4, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097228: CREATE_BUFFER]
D3D11 INFO: Create ID3D11Buffer: Name="unnamed", Addr=0x028F00DC, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097228: CREATE_BUFFER]
D3D11 INFO: Create ID3D11Texture2D: Name="unnamed", Addr=0x028F0974, ExtRef=1, IntRef=0 [ STATE_CREATION INFO #2097234: CREATE_TEXTURE2D]
The program '[8292] Minimal application.exe' has exited with code 0 (0x0).

I've tried out switching the input parameters for the ResolveSubResource.

It works :) Thanks.

 

The confusion came from this, what I found at in an old topic:

Posted 25 April 2012 - 10:35 PM 
So what you want to do is bind that render target view, render to it, and then use DeviceContext.ResolveSubresource using the MSAA render target texture as the source and the backbuffer texture as the destination. This will resolve the MSAA render target (filter the individual MSAA subsamples), and copy the results to the backbuffer. 

Which actually is correct / like you said, I've just mixed them up (read to quickly 'resource' as 'source' :))

Share this post


Link to post
Share on other sites

Strange. You should've been getting this error:

    if( DstDesc.Usage != D3D11_USAGE_DEFAULT ||
        DstDesc.BindFlags & D3D11_BIND_DEPTH_STENCIL ||
        DstDesc.Samples != 1 )
    {
        fnSentinel.ReportMessage( D3D11_MESSAGE_ID_DEVICE_RESOLVESUBRESOURCE_DESTINATION_INVALID,
            "Destination Resource must be a D3D11_USAGE_DEFAULT, without multisampling, and without the BIND_DEPTH_STENCIL flag. "
            "The Destination Resource has %u samples.",
            DstDesc.Samples );
    }

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

Sign in to follow this