Skip to main content
GameDev.net gamedev.net
🔒 Locked

SwapChain resize questions

Started by BlackJoker Jan 18, 2014 at 4:57 PM 16 replies 8.9k views
Original Post
BlackJoker
BlackJoker

I have few questions regarding swapchain resizing:

First question:

I made resizing just like in MSDN article, but seems it works not fully correct.

After resizing back of my model begin to be visible from front. You can look this at screenshots

[attachment=19533:before_res.png]

[attachment=19534:after_res.png]

[attachment=19535:result.png]

first screenshot - before resizing

second - after

third - how it displays in another angle.

Looks like stencil operation not working. Here is the code of my swapchain resizing:


void D3D11::ResizeSwapChain()
{
	if (swapChain)
	{
		DeinitializeD2D11();
		RECT rc;
		GetClientRect(hwnd, &rc);
		UINT width = rc.right - rc.left;
		UINT height = rc.bottom - rc.top;

		d3d11_DeviceContext->OMSetRenderTargets(0, 0, 0);

		// Release all outstanding references to the swap chain's buffers.
		d3d11_RenderTargetView->Release();

		HRESULT hr;
		// Preserve the existing buffer count and format.
		// Automatically choose the width and height to match the client rect for HWNDs.
		hr = swapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);


		// Perform error handling here!

		// Get buffer and create a render-target-view.
		ID3D11Texture2D* pBuffer;
		hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
			(void**)&pBuffer);
		// Perform error handling here!

		hr = d3d11_Device->CreateRenderTargetView(pBuffer, NULL,
			&d3d11_RenderTargetView);
		// Perform error handling here!
		pBuffer->Release();

		d3d11_DeviceContext->OMSetRenderTargets(1, &d3d11_RenderTargetView, NULL);

		// Set up the viewport.
		D3D11_VIEWPORT viewPort;

		viewPort.Width = (float)width;
		viewPort.Height = (float)height;
		viewPort.MinDepth = 0.0f;
		viewPort.MaxDepth = 1.0f;
		viewPort.TopLeftX = 0.0f;
		viewPort.TopLeftY = 0.0f;
		d3d11_DeviceContext->RSSetViewports(1, &viewPort);

		InitializeD2D11();
	}
}

And second question:

if I created swapchain with 2 or more buffers, is this code correct in this case or I need do some changes to correctly resize all buffers?

pcmaster
pcmaster

Looks like you don't set a depth-buffer (depth-stencil view, the final parameter of OMSetRenderTargets) anymore. Provided that you show us all.

BlackJoker
BlackJoker

I can do like this:




if (swapChain)
	{
		DeinitializeD2D11();
		RECT rc;
		GetClientRect(hwnd, &rc);
		UINT width = rc.right - rc.left;
		UINT height = rc.bottom - rc.top;

		d3d11_DeviceContext->OMSetRenderTargets(0, 0, 0);

		// Release all outstanding references to the swap chain's buffers.
		d3d11_RenderTargetView->Release();

		HRESULT hr;
		// Preserve the existing buffer count and format.
		// Automatically choose the width and height to match the client rect for HWNDs.
		hr = swapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);


		// Perform error handling here!

		// Get buffer and create a render-target-view.
		ID3D11Texture2D* pBuffer;
		hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
			(void**)&pBuffer);

		
		// Perform error handling here!

		hr = d3d11_Device->CreateRenderTargetView(pBuffer, NULL,
			&d3d11_RenderTargetView);
		// Perform error handling here!
		
		//?????????????? ???????? ????????? Depth_Buffer
		ZeroMemory(&depthBufferDescription, sizeof(depthBufferDescription));

		//????????? ???????? ?????????
		depthBufferDescription.Width = width;
		depthBufferDescription.Height = height;
		depthBufferDescription.MipLevels = 1;
		depthBufferDescription.ArraySize = 1;
		depthBufferDescription.Format = DXGI_FORMAT_D32_FLOAT;
		depthBufferDescription.SampleDesc.Count = 4;
		depthBufferDescription.SampleDesc.Quality = 0;
		depthBufferDescription.Usage = D3D11_USAGE_DEFAULT;
		depthBufferDescription.BindFlags = D3D11_BIND_DEPTH_STENCIL;
		depthBufferDescription.CPUAccessFlags = 0;
		depthBufferDescription.MiscFlags = 0;

		d3d11_DepthStencilBuffer->Release();
		d3d11_DepthStencilBuffer = NULL;

		//??????? ???????? ??? ?????? ??????? ????????? ??????????? ?????????
		d3d11_Device->CreateTexture2D(&depthBufferDescription, NULL, &d3d11_DepthStencilBuffer);

		//?????? ????????? Depth Stencil State
		d3d11_DeviceContext->OMSetDepthStencilState(d3d11_DepthStencilState, 1);

		//?????????????? ????????? Depth Stencil View
		ZeroMemory(&depthStencilViewDescription, sizeof(depthStencilViewDescription));

		//????????? ???????? ????????? Depth_Stencil_View
		depthStencilViewDescription.Format = DXGI_FORMAT_D32_FLOAT;
		depthStencilViewDescription.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
		depthStencilViewDescription.Texture2D.MipSlice = 0;

		d3d11_DepthStencilView->Release();
		d3d11_DepthStencilView = NULL;

		//?????? ???????? ????????? Depth_Stencil_View
		d3d11_Device->CreateDepthStencilView(d3d11_DepthStencilBuffer, &depthStencilViewDescription, &d3d11_DepthStencilView);

		d3d11_DeviceContext->OMSetRenderTargets(1, &d3d11_RenderTargetView, d3d11_DepthStencilView);

		//d3d11_DeviceContext->OMSetRenderTargets(1, &d3d11_RenderTargetView, d3d11_DepthStencilView);
		pBuffer->Release();
		// Set up the viewport.
		D3D11_VIEWPORT viewPort;

		viewPort.Width = (float)width;
		viewPort.Height = (float)height;
		viewPort.MinDepth = 0.0f;
		viewPort.MaxDepth = 1.0f;
		viewPort.TopLeftX = 0.0f;
		viewPort.TopLeftY = 0.0f;
		d3d11_DeviceContext->RSSetViewports(1, &viewPort);

		InitializeD2D11();
	}

But this leads to flickering of meshes during resizing.

Auskennfuchs
Auskennfuchs

I had the same issue, when I implemented the resizing and also got some ugly synchronization problems up to bluescreens from graphiccard-driver, cause I rendered in another thread to the window-messagequeue and called the resize-function on every WM_MOVE event.

When you trigger your resizefunction? I guess the order Drawing->Present->Resize or Resize->Drawing->Present should reduce flickering. In my solution I ended up in just resize the textures when resize is finished. So the rendered image gets scaled while resizing and corrected just once afterwards.

BlackJoker
BlackJoker

Auskennfuchs

I trigger my function before drawing. After your advice I move triggering after Present. Flickering reduced a little, but is not gone. How to completely remove it? It is interesting that if not recreate depth buffer during resizing, flickering will completely removed, but this will lead to loss of depth.

pcmaster
pcmaster

Just in case, I'd try clearing both buffers (textures) of the swap chain, if you have two, just after calling ResizeBuffers and before OMSetRenderTargets. You could use ID3D11DeviceContext::ClearRenderTargetView on your RTV, or Map, or UpdateSubresource or anything.

BlackJoker
BlackJoker

pcmaster

could you please give a little code sample regarding my situation?

pcmaster
pcmaster

Something like this:


        ID3D11Texture2D* pBuffer;
        hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBuffer);
        ID3D11Texture2D* pBuffer2;
        hr = swapChain->GetBuffer(1, __uuidof(ID3D11Texture2D), (void**)&pBuffer2); // the second buffer which might contain random data

        hr = d3d11_Device->CreateRenderTargetView(pBuffer, nullptr, &d3d11_RenderTargetView); // RTV for swap buffer "0"
        hr = d3d11_Device->CreateRenderTargetView(pBuffer2, nullptr, &tmpRTV2); // a TEMPORARY RTV for swap buffer "1"
        d3d11_DeviceContext->ClearRenderTargetView(d3d11_RenderTargetView, black); // clear everything, just in case
        d3d11_DeviceContext->ClearRenderTargetView(tmpRTV2, black); // black is 4 floats of 0
        pBuffer->Release();
        pBuffer2->Release();

        d3d11_DeviceContext->OMSetRenderTargets(1, &d3d11_RenderTargetView, d3d11_DepthStencilView);

This is just a blind shot, might not be the problem (it is on the newest consoles).

Also mind checking your initialize methods, if you don't reset some state that you don't want to reset.

BlackJoker
BlackJoker

Here is my initialize method.

Not sure that I work with 2 buffers correctly:


UINT numFeatureLevels = ARRAYSIZE(featureLevels);
	factory->EnumAdapters(0,&adapter);
	//??????? ?????????? Direct3D ? ???????? ?????????? Direct3D
	result = D3D11CreateDevice(adapterList[0]->adapter, driverType, NULL, D3D11_CREATE_DEVICE_DEBUG|D3D11_CREATE_DEVICE_BGRA_SUPPORT, featureLevels,numFeatureLevels,
		D3D11_SDK_VERSION, &d3d11_Device, &featureLevel, &d3d11_DeviceContext );

	if (FAILED(result))
	{
		return false;
	}
	UINT qualityLevels;
	result = d3d11_Device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, 8, &qualityLevels);


	//?????????????? ????????? swap chain description
	ZeroMemory(&swapChainDescription, sizeof(swapChainDescription));
	

	//????????????? ?????????? ???????
	swapChainDescription.BufferCount = 2;

	//????????????? ?????? ? ?????? ??????? ??????
	swapChainDescription.Width = settingsContainer->renderSettingsDX11->GetScreenWidth();
	swapChainDescription.Height = settingsContainer->renderSettingsDX11->GetScreenHeight();

	//????????????? ?????? ????????
	swapChainDescription.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

	swapChainDescription.SampleDesc.Count = 4;
	swapChainDescription.SampleDesc.Quality = 0;

	//????????????? ????????????? ??????? ??????
	swapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapChainDescription.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
	swapChainDescription.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;

	DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen;
	fullscreen.RefreshRate.Numerator = 60;
	fullscreen.RefreshRate.Denominator = 1;
	fullscreen.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
	fullscreen.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
	//????????????? ? ????????????? ????? ? ???????
	if (settingsContainer->renderSettingsDX11->IsFullScreenEnabled())
	{
		fullscreen.Windowed = FALSE;
	}
	else
	{
		fullscreen.Windowed = TRUE;
	}
	
	

	//??????? swap chain
	result = factory->CreateSwapChainForHwnd(d3d11_Device, hwnd, &swapChainDescription, &fullscreen, NULL, &swapChain);
	if(FAILED(result))
		return false;
	
	//???????? ????????? ?? ?????? ?????
	result = swapChain->GetBuffer(0,__uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr);
	if (FAILED(result))
		return false;

	
	//??????? render target view ? ?????????? ?? ?????? ?????
	result = d3d11_Device->CreateRenderTargetView(backBufferPtr, NULL, &d3d11_RenderTargetView);
	if(FAILED(result))
		return false;
	
	//??????????? ????????? ?? ?????? ?????, ??? ??? ?? ?????? ?? ?????
	backBufferPtr->Release();
	backBufferPtr = 0;

	//?????????????? ???????? ????????? Depth_Buffer
	ZeroMemory(&depthBufferDescription, sizeof(depthBufferDescription));

	//????????? ???????? ?????????
	depthBufferDescription.Width = settingsContainer->renderSettingsDX11->GetScreenWidth();
	depthBufferDescription.Height = settingsContainer->renderSettingsDX11->GetScreenHeight();
	depthBufferDescription.MipLevels = 1;
	depthBufferDescription.ArraySize = 1;
	depthBufferDescription.Format = DXGI_FORMAT_D32_FLOAT;
	depthBufferDescription.SampleDesc.Count = 4;
	depthBufferDescription.SampleDesc.Quality = 0;
	depthBufferDescription.Usage = D3D11_USAGE_DEFAULT;
	depthBufferDescription.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	depthBufferDescription.CPUAccessFlags = 0;
	depthBufferDescription.MiscFlags = 0;

	//??????? ???????? ??? ?????? ??????? ????????? ??????????? ?????????
	result = d3d11_Device->CreateTexture2D(&depthBufferDescription, NULL, &d3d11_DepthStencilBuffer);
	if (FAILED(result))
		return false;
		


	//?????????????? ???????? stencil state
	ZeroMemory(&depthStencilDescription, sizeof(depthStencilDescription));

	//?????? ???????? ????????? stencil_state
	depthStencilDescription.DepthEnable = true;
	depthStencilDescription.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
	depthStencilDescription.DepthFunc = D3D11_COMPARISON_LESS;

	depthStencilDescription.StencilEnable = true;
	depthStencilDescription.StencilReadMask = 0xFF;
	depthStencilDescription.StencilWriteMask = 0xFF;

	//????????? ???????? ???? ??????? ???????
	depthStencilDescription.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDescription.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
	depthStencilDescription.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDescription.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

	//????????? ????????, ???? ??????? ?? ???????? ???????
	depthStencilDescription.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDescription.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
	depthStencilDescription.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDescription.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
	
	//??????? Depth_Stencil_State
	result = d3d11_Device->CreateDepthStencilState(&depthStencilDescription, &d3d11_DepthStencilState);
	if (FAILED(result))
	{
		return false;
	}
	//?????? ????????? Depth Stencil State
	d3d11_DeviceContext->OMSetDepthStencilState(d3d11_DepthStencilState,1);
	
	//?????????????? ????????? Depth Stencil View
	ZeroMemory (&depthStencilViewDescription, sizeof(depthStencilViewDescription));
	
	//????????? ???????? ????????? Depth_Stencil_View
	depthStencilViewDescription.Format = DXGI_FORMAT_D32_FLOAT;
	depthStencilViewDescription.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
	depthStencilViewDescription.Flags = 0;

	//?????? ???????? ????????? Depth_Stencil_View
	result = d3d11_Device->CreateDepthStencilView(d3d11_DepthStencilBuffer, &depthStencilViewDescription, &d3d11_DepthStencilView);
	if (FAILED(result))
		return false;

	//??????????? render target view ? depth stencil buffer ? output pipeline
	d3d11_DeviceContext->OMSetRenderTargets(1, &d3d11_RenderTargetView, d3d11_DepthStencilView);

	//????????? ????????? Raster_Description, ??????? ????? ?????????? ??? ? ????? ???????? ????? ??????????
	rasterizerDescription.AntialiasedLineEnable = true;
	rasterizerDescription.CullMode = D3D11_CULL_BACK;
	rasterizerDescription.DepthBias = 0;
	rasterizerDescription.DepthBiasClamp = 0.0f;
	rasterizerDescription.DepthClipEnable = true;
	rasterizerDescription.FillMode = D3D11_FILL_SOLID;
	rasterizerDescription.FrontCounterClockwise = false;
	rasterizerDescription.MultisampleEnable = true;
	rasterizerDescription.ScissorEnable = false;
	rasterizerDescription.SlopeScaledDepthBias = 0.0f;

	//??????? rasterizerState ?? ????????, ??????? ?????? ??? ?????????
	result = d3d11_Device->CreateRasterizerState(&rasterizerDescription, &d3d11_RasterizerStateSolid);
	if(FAILED(result))
	{
		return false;
	}
	
	//????????????? rasterizer state (????? ?????? ????????? ? D3D11_FILL_SOLID ?? D3D11_FILL_WIREFRAME)
	d3d11_DeviceContext->RSSetState(d3d11_RasterizerStateSolid);

	//????????? ????????? Raster_Description, ??????? ????? ?????????? ??? ? ????? ???????? ????? ??????????
	rasterizerDescription.AntialiasedLineEnable = true;
	rasterizerDescription.CullMode = D3D11_CULL_NONE;
	rasterizerDescription.DepthBias = 0;
	rasterizerDescription.DepthBiasClamp = 0.0f;
	rasterizerDescription.DepthClipEnable = true;
	rasterizerDescription.FillMode = D3D11_FILL_WIREFRAME;
	rasterizerDescription.FrontCounterClockwise = false;
	rasterizerDescription.MultisampleEnable = true;
	rasterizerDescription.ScissorEnable = false;
	rasterizerDescription.SlopeScaledDepthBias = 0.0f;

	//??????? rasterizerState ?? ????????, ??????? ?????? ??? ?????????
	result = d3d11_Device->CreateRasterizerState(&rasterizerDescription, &d3d11_RasterizerStateWireFrame);
	if(FAILED(result))
	{
		return false;
	}

	//????????????? ??????? ??? ??????????
	viewPort.Width = (float)settingsContainer->renderSettingsDX11->GetScreenWidth();
	viewPort.Height = (float)settingsContainer->renderSettingsDX11->GetScreenHeight();
	viewPort.MinDepth = 0.0f;
	viewPort.MaxDepth = 1.0f;
	viewPort.TopLeftX = 0.0f;
	viewPort.TopLeftY = 0.0f;

	//??????? ViewPort
	d3d11_DeviceContext->RSSetViewports(1,&viewPort);
BlackJoker
BlackJoker

And another one issue. I justed noticed That if I made resizing just like I did before, but if OMSetRenderTargets will contain depth-StencilView, then my mesh disapper if I make window bigget that it was and appear, if I make window smaller, that it was. Is it Correct behavior?


RECT rc;
		GetClientRect(hwnd, &rc);
		UINT width = rc.right - rc.left;
		UINT height = rc.bottom - rc.top;

		d3d11_DeviceContext->OMSetRenderTargets(0, 0, 0);

		// Release all outstanding references to the swap chain's buffers.
		d3d11_RenderTargetView->Release();

		HRESULT hr;
		// Preserve the existing buffer count and format.
		// Automatically choose the width and height to match the client rect for HWNDs.
		hr = swapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);


		// Perform error handling here!

		// Get buffer and create a render-target-view.
		ID3D11Texture2D* pBuffer;
		hr = swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
			(void**)&pBuffer);

		
		// Perform error handling here!

		hr = d3d11_Device->CreateRenderTargetView(pBuffer, NULL,
			&d3d11_RenderTargetView);
		
		d3d11_DeviceContext->OMSetRenderTargets(1, &d3d11_RenderTargetView, d3d11_DepthStencilView);
		pBuffer->Release();
		// Set up the viewport.
		D3D11_VIEWPORT viewPort;

		viewPort.Width = (float)width;
		viewPort.Height = (float)height;
		viewPort.MinDepth = 0.0f;
		viewPort.MaxDepth = 1.0f;
		viewPort.TopLeftX = 0.0f;
		viewPort.TopLeftY = 0.0f;
		d3d11_DeviceContext->RSSetViewports(1, &viewPort);

As i underatnd resizeBuffer function resizes depthBuffer also? If so, Why in this case mesh just disappears after resizing?

pcmaster
pcmaster

No, you misunderstand. IDXGISwapChain::ResizeBuffers only resizes the swapchain. It knows nothing about your depth/stencil buffers. It is DXGI, not D3D. You can have dozens of various depth/stencil target buffers and dozens of color targets but you only have one swap chain (with two buffers, here). OMSetRenderTargets sets a combination for subsequent D3D11 rendering commands and you can (and eventually will) call it with different combinations during a frame. Do you understand, what it does?

So, you must also resize (meaning release and recreate) all other textures you're using as rendering targets with the swap chain buffers. That is, resize your depth/stencil, too! smile.png

BlackJoker
BlackJoker

yes, now I understand, but what is cause for flickering? That the thing I cannot understand. I am not rendering during resizing, so what happening here? Is it because of recreation of depth/stencil? And for now I still cannot get rid of this even with your solution. My initialization method is in post #9.

pcmaster
pcmaster

And how is it flickering exactly?

BlackJoker
BlackJoker

background is not flickering at all. Flickering only loaded meshes and only when I make window bigger. When I make window smaller - there is no such issue. I don`t know how exactly describe flickering, but it seems that meshes just disappear and appear again in few milliseconds.

Erik Rufelt
Erik Rufelt

How do you create your window and window-class?

Make sure to have NULL as the background brush in window-class, and remove CS_HREDRAW and similar if you have them.

I would use ClearState in resize and then reset everything after:


// Release
pDeviceContext->ClearState();
pRenderTargetView->Release();
pDepthStencilView->Release();// Release both buffer and view
pDepthStencilBuffer->Release();// Release both buffer and view

// Resize
pSwapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);

// New back-buffer and render-target view
ID3D11Texture2D pBackBuffer;
pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBackBuffer);

ID3D11RenderTargetView pRenderTargetView;
pDevice->CreateRenderTargetView(pBackBuffer, ..., &pRenderTargetView);

// Save desc before release backbuffer
D3D11_TEXTURE2D_DESC;
pBackBuffer->GetDesc(&backBufferDesc);

pBackBuffer->Release();


// New depth-stencil
D3D11_TEXTURE2D_DESC depthStencilDesc = backBufferDesc;
depthStencilDesc.Format = DEPTH FORMAT;
...

pDevice->CreateTexture2D(&depthStencilDesc, &pDepthStencilBuffer);

pDevice->CreateDepthStencilVile(pDepthStencilBuffer, &pDepthStencilView);


// Set render target
pDeviceContext->OMSetRenderTargets(pRenderTargetView, pDepthStencilView);

// Set everything else
pDeviceContext->.. SetViewport(...);
pDeviceContext->.. SetDepthStencilState(...);
pDeviceContext->.. SetRasterizerState(...);
pDeviceContext->.. Set........(...);

BlackJoker
BlackJoker

Erik Rufelt

Your solution working great. Meshes not flickering any more, but I don`t understand what was the cause.

ALso I have another questuon regarding 2 or more buffers. Do I need to handle this in some special way and resize both buffers or resizing one buffer I automatically resize all other?

Erik Rufelt
Erik Rufelt

No, it is handled by the swap-chain and you shouldn't have to care at all, you still use only one render-target.

Also, you're only resizing the swap-chain, and the swap-chain in turn resizes its buffers and anything else that might be needed for its internal workings. Just make sure to release all references to the back-buffer before resizing the swap-chain (as you already do).

BlackJoker
BlackJoker

I understand. Thanks for help a lot!!!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.