• Advertisement
Sign in to follow this  

Changing MSAA settings on the fly

This topic is 522 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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
Advertisement

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

You are correct.

 

You just forgot the step calling the function below ( or writing your own resolve shader as it can be useful to do it yourself sometimes )

ID3D11DeviceContext::ResolveSubresource

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)

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
Sign in to follow this  

  • Advertisement