Can't release BackBuffer before calling SwapChain->ResizeBuffers

Started by
6 comments, last by Dissipate 9 years, 1 month ago

Hi,

I am trying to resize the window. I managed it before in another project (dx11 this is dx11.1) but I just can't seem to find the outstanding reference that is needed to be released before resizing the swap chain. I get the error in the output window:

DXGI ERROR: IDXGISwapChain::ResizeBuffers: Swapchain cannot be resized unless all outstanding buffer references have been released. [ MISCELLANEOUS ERROR #19: ]
DXGI ERROR: IDXGISwapChain::ResizeBuffers: Swapchain cannot be resized unless all outstanding buffer references have been released. [ MISCELLANEOUS ERROR #19: ]

I have already seen the following links that cover this in a little detail:

https://msdn.microsoft.com/en-us/library/windows/desktop/bb205075%28v=vs.85%29.aspx#Handling_Window_Resizing and Gamedev_Duplicate_Post_Here and

Another_Duplicate_Here.

In the last one Erik Rufelt explains in post #17 that all references to the backbuffer must be released. The only place that I would have had a reference would have been the Direct2D class (CD2DObj), for drawing a textured quad, but I cut it out and now I'm just displaying a coloured screen. Here is the ::OnResize code that is called at the end of ::InitDirect3D and also in MsgProc's WM_SIZE handler:

Additional: On start up the this is called but does not seem to get released as I check with the swapchain's addref/release pairs periodically. Also I am creating the swapchain with backbuffer count of 1.


	try
	{
		assert(m_spD3DImmediateContext);
		assert(m_spD3DDevice);
		assert(m_spSwapChain);

		//ReleaseCOM(m_pRenderTargetView);
		//ReleaseCOM(m_pDepthStencilView);
		//ReleaseCOM(m_spDepthStencilBuffer);
		//m_spRenderTargetView.Reset();
		//m_spDepthStencilView.Reset();
		//m_spDepthStencilBuffer.Reset();
		//m_spDepthDisabledStencilState.Reset();

		// This is used to monitor the reference count
		auto Myref = m_spSwapChain->AddRef();
		Myref = m_spSwapChain->Release();

		ULONG RefCount = 0;

		//if (m_spDepthEnabledStencilState)
		//	RefCount = m_spDepthEnabledStencilState->Release();
		//assert(RefCount == 0); // Fails = 1
		//if (m_spDepthDisabledStencilState)
		//	RefCount = m_spDepthDisabledStencilState->Release();
		//assert(RefCount == 0);		
		m_spD3DImmediateContext->OMSetRenderTargets(0, 0, 0);	

		if (m_spDepthStencilView)
			RefCount = m_spDepthStencilView->Release();
		assert(RefCount == 0);
		if (m_spDepthStencilBuffer)
			RefCount = m_spDepthStencilBuffer->Release();
		assert(RefCount == 0);
		if (m_spRenderTargetView)
			RefCount = m_spRenderTargetView->Release();
		assert(RefCount == 0);

		//m_spRenderTargetView.Reset();
		//m_spDepthStencilView.Reset();
		//m_spDepthStencilBuffer.Reset();
		//m_spDepthDisabledStencilState.Reset();

		//assert(m_spRenderTargetView == nullptr);
		//assert(m_spDepthStencilView == nullptr);
		//assert(m_spDepthStencilBuffer == nullptr);
		//assert(m_spDepthDisabledStencilState == nullptr);

		Myref = m_spSwapChain->AddRef();
		Myref = m_spSwapChain->Release();
		
		// Resize the swap chain and recreate the render target view.
		COMERR(m_spSwapChain->ResizeBuffers(1, m_iClientWidth, m_iClientHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0),
			"CD3DObject::OnResize() SwapChain Could not resize.");
		ID3D11Texture2D* pBackBuffer;
		COMERR(m_spSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pBackBuffer)),
			"CD3DObject::OnResize() SwapChain could not get backbuffer.");
		COMERR(m_spD3DDevice->CreateRenderTargetView(pBackBuffer, 0, m_spRenderTargetView.GetAddressOf()),
			"CD3DObject::OnResize() Could not re-create render target view.");

		Myref = m_spSwapChain->AddRef();
		Myref = m_spSwapChain->Release();

		//ReleaseCOM(pBackBuffer);
		RefCount = pBackBuffer->Release();

		Myref = m_spSwapChain->AddRef();
		Myref = m_spSwapChain->Release();

Advertisement

I had trouble resizing for awhile as well, but I'm not entirely sure it was the same problem for me. Mine turned out to be some SRVs I had forgotten about.

I tracked it down by using the DebugName parameter on SharpDX's SRVs. I think C++ has something similar. I can't remember if I had to call something to get the debug spew to report it or if it just happens. This link has some info: http://blogs.msdn.com/b/chuckw/archive/2012/11/30/direct3d-sdk-debug-layer-tricks.aspx

Thanks Kbaird.

I have implemented the debug layer and am logging the addresses of my variables and still at a lost as to why there is an extra mysterious RenderTargetView appearing at a differant address at the time of creation - after the swapchain resize. I can release the backbuffer by releasing it twice thereby remaining as 2 internal references.

Here is a report right after I create the rendertargetview/resize swapchain and release the pBackBuffer twice:


D3D11 WARNING: Live ID3D11Device at 0x000000000013D880, Name: CD3DObject::m_spD3DDevice, Refcount: 10 [ STATE_CREATION WARNING #441: LIVE_DEVICE]
D3D11 WARNING: 	Live ID3D11Context at 0x0000000000143A00, Name: CD3DObject::m_spD3DImmediateContext, Refcount: 1, IntRef: 1 [ STATE_CREATION WARNING #2097226: LIVE_CONTEXT]
D3D11 WARNING: 	Live ID3DDeviceContextState at 0x000000000015B770, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #3145742: LIVE_DEVICECONTEXTSTATE]
D3D11 WARNING: 	Live ID3D11BlendState at 0x0000000000166AD0, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #435: LIVE_BLENDSTATE]
D3D11 WARNING: 	Live ID3D11DepthStencilState at 0x0000000000167090, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #436: LIVE_DEPTHSTENCILSTATE]
D3D11 WARNING: 	Live ID3D11RasterizerState at 0x00000000001672B0, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #437: LIVE_RASTERIZERSTATE]
D3D11 WARNING: 	Live ID3D11Sampler at 0x00000000001675D0, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #434: LIVE_SAMPLER]
D3D11 WARNING: 	Live ID3D11Query at 0x0000000000167850, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #438: LIVE_QUERY]
D3D11 WARNING: 	Live IDXGISwapChain at 0x0000000000167A30, Name: CD3DObject::m_spSwapChain, Refcount: 1 [ STATE_CREATION WARNING #442: LIVE_SWAPCHAIN]
D3D11 WARNING: 	Live ID3D11Texture2D at 0x0000000000168190, Refcount: 0, IntRef: 2 [ STATE_CREATION WARNING #425: LIVE_TEXTURE2D]
D3D11 WARNING: 	Live ID3D11RenderTargetView at 0x0000000000168910, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #428: LIVE_RENDERTARGETVIEW]
D3D11 WARNING: 	Live ID3D11RenderTargetView at 0x0000000000168D10, Name: CD3DObject::m_spRenderTargetView, Refcount: 1, IntRef: 0 [ STATE_CREATION WARNING #428: LIVE_RENDERTARGETVIEW]

Can anyone suggest how to find and release the RTV at address 0x0000000000168910. Oh man - do I need a good resource manager! One that logs the address of every resource.

Tried to follow this advice but to no avail -> https://msdn.microsoft.com/en-us/library/windows/desktop/bb174577%28v=vs.85%29.aspx.

I understand your frustration, but hacking isn't the correct approach. I.e., arbitrarily releasing objects here and there to "make it work" will only confuse the issue. I.e.,

I create the rendertargetview/resize swapchain and release the pBackBuffer twice:

Why are you releasing it TWICE? You're hacking, rather than finding and correcting the problem.

Take a structured approach to debugging.

First: remove all the AddRef/Release code, remove all the other hacking code, etc.

Second: examine the data in your app step-by-step to determine where correct data turns to bad data.

E.g.,

0. Comment out all calls to Resize except at the end of your init-device routine (WM_EXITSIZEMOVE or WM_SIZE, etc.).

1. create the window.

2. create the swapchain and device/context.

N.B., don't create the rendertargetview, backbuffer texture, depthstencilview or viewport in your init routine. You do all that in the resize routine anyway.

3. call debugDevice->ReportLiveObjects

4. call your resize routine.

If ResizeBuffers works correctly at that point, then somewhere else in the code that's executed after that you bind the rendertargetview somewhere.

EDIT: lined out the repetition caused by the Deptartment of Redundancy Department.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Thanks Buckeye.


Why are you releasing it TWICE? You're hacking, rather than finding and correcting the problem.

The problem is that I don't understand the inner workings of DirectX. But you are right I found out that if I start releasing things over and over then I can corrupt the heap and then unreproducible stuff starts happening. Incorrect releasing of resources can also cause ID3D11Device1 and ID3D11DeviceContext1 to break on internal release upon destruction because of a null pointer.

The problem was that somehow ComPtr was pre-creating a Texture2D that needed to be released before Getting the backbuffer from the swapchain. The same goes for the RenderTargetView. Using:


.ReleaseAndGetAddressOf()

I had placed Livereporting before and after every call so that I could track where and what was causing the problem. It also helped me ascertain exactly what needed to be released after a WM_SIZE and before a SwapChain->Resize. Be careful not to make the same mistake that I made where I was looking at the summary of the live report and pulling out my hair trying to find the outstanding references. You need to look at the detailed part and release the external refs. That's probably obvious to everyone but it had me going round in circles for a few days!

Problem solved, thanks yet again for your valuable insight and mentoring encouragement Buckeye smile.png

Sorry guys, I haven't managed to solve this yet. To recap:

The Problem (Error):



DXGI ERROR: IDXGISwapChain::ResizeBuffers: Swapchain cannot be resized unless all outstanding buffer references have been released. [ MISCELLANEOUS ERROR #19: ]
DXGI ERROR: IDXGISwapChain::ResizeBuffers: Swapchain cannot be resized unless all outstanding buffer references have been released. [ MISCELLANEOUS ERROR #19: ]
First-chance exception at 0x000007FEFC93940D in DXTBApplication.exe: Microsoft C++ exception: CException at memory location 0x000000000027CBF0.

Notice that I get 2 error messages! The site of the problem is CD3DObject::OnResize():


		m_spD3DImmediateContext->ClearState();

		//CRenderStates::ResetAll();

		//if (m_spDepthEnabledStencilState)
		//	RefCount = m_spDepthEnabledStencilState->Release();
		//assert(RefCount == 0);
		//if (m_spDepthDisabledStencilState)
		//	RefCount = m_spDepthDisabledStencilState->Release();
		//assert(RefCount == 0);

		if (m_spDepthStencilView)
			m_spDepthStencilView.Reset();
		if (m_spRenderTargetView)
			m_spRenderTargetView.Reset();
		if (m_spDepthStencilBuffer)
			m_spDepthStencilBuffer.Reset();
		if (m_spDepthEnabledStencilState)
			m_spDepthEnabledStencilState.Reset();
		if (m_spDepthDisabledStencilState)
			m_spDepthDisabledStencilState.Reset();

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



		LOGADDRESS_SP(m_spD3DDevice.Get());
		LOGADDRESS_SP(m_spD3DImmediateContext.Get());
		LOGADDRESS_SP(m_spSwapChain.Get());
		LOGADDRESS_SP(m_spDepthStencilBuffer.Get());
		LOGADDRESS_SP(m_spRenderTargetView.Get());
		LOGADDRESS_SP(m_spDepthStencilView.Get());
		LOGADDRESS_SP(m_spDepthEnabledStencilState.Get());
		LOGADDRESS_SP(m_spDepthDisabledStencilState.Get());
		LOGADDRESS_SP(m_spSwapChain.Get());

		m_spD3DImmediateContext->Flush();
		
		LIVE_REPORT

		// Resize the swap chain and recreate the render target view.
		COMERR(m_spSwapChain->ResizeBuffers(1, m_iClientWidth, m_iClientHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0),
			"CD3DObject::OnResize() SwapChain Could not resize.");
		LIVE_REPORT
		ComPtr<ID3D11Texture2D> spBackBuffer;
		COMERR(m_spSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(spBackBuffer.GetAddressOf())),
			"CD3DObject::OnResize() SwapChain could not get backbuffer 0.");
		LIVE_REPORT
		COMERR(m_spD3DDevice->CreateRenderTargetView(spBackBuffer.Get(), 0, m_spRenderTargetView.GetAddressOf()),
			"CD3DObject::OnResize() Could not re-create render target view.");
		SETPRIVATEDATA(m_spRenderTargetView, "CD3DObject::m_spRenderTargetView");
		LIVE_REPORT

		spBackBuffer.Reset();
		LOGADDRESS_SP(spBackBuffer.Get());
		LIVE_REPORT

The Live_Report at line 381 after the GetBuffer shows a RefCount of 2. As I go along creating RTVs and DepthViews and DeptStencilStates, I create 2 of each!?! One with the DebugName (privatedata) that I give it and one unassigned at a different address. I went through my code looking for where I might be duplicating the class somewhere. I RefCounted my CD3DObject class asserted it as "RefCount == 1 " in the constructor. Also I now return raw pointers from all 'Get' functions instead of previously returning smart pointer references. The only other change I can think of, from my previous version (which works fine), is that I made the engine a .lib project. Here is the Live_Report at line 381:


CD3DObject::OnResize(381) Creating Live Report Here...
D3D11 WARNING: Live ID3D11Device at 0x00000000003AA180, Name: CD3DObject::m_spD3DDevice, Refcount: 7 [ STATE_CREATION WARNING #441: LIVE_DEVICE]
D3D11 WARNING: 	Live ID3D11Context at 0x000000000038F9B0, Name: CD3DObject::m_spD3DImmediateContext, Refcount: 2, IntRef: 1 [ STATE_CREATION WARNING #2097226: LIVE_CONTEXT]
D3D11 WARNING: 	Live ID3DDeviceContextState at 0x00000000003AB6D0, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #3145742: LIVE_DEVICECONTEXTSTATE]
D3D11 WARNING: 	Live ID3D11BlendState at 0x00000000003B6A30, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #435: LIVE_BLENDSTATE]
D3D11 WARNING: 	Live ID3D11DepthStencilState at 0x00000000003A6190, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #436: LIVE_DEPTHSTENCILSTATE]
D3D11 WARNING: 	Live ID3D11RasterizerState at 0x00000000003A63F0, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #437: LIVE_RASTERIZERSTATE]
D3D11 WARNING: 	Live ID3D11Sampler at 0x00000000003A6710, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #434: LIVE_SAMPLER]
D3D11 WARNING: 	Live ID3D11Query at 0x00000000003A6990, Refcount: 0, IntRef: 1 [ STATE_CREATION WARNING #438: LIVE_QUERY]
D3D11 WARNING: 	Live IDXGISwapChain at 0x00000000003A6B70, Name: CD3DObject::m_spSwapChain, Refcount: 2 [ STATE_CREATION WARNING #442: LIVE_SWAPCHAIN]
D3D11 WARNING: 	Live ID3D11Texture2D at 0x00000000003A7320, Name: CD3DObject::spBackBuffer, Refcount: 2, IntRef: 0 [ STATE_CREATION WARNING #425: LIVE_TEXTURE2D]
D3D11 WARNING: Live                  ID3D11Context :      1 [ STATE_CREATION WARNING #422: LIVE_OBJECT_SUMMARY]
D3D11 WARNING: Live         ID3DDeviceContextState :      1 [ STATE_CREATION WARNING #422: LIVE_OBJECT_SUMMARY]
D3D11 WARNING: Live               ID3D11BlendState :      1 [ STATE_CREATION WARNING #422: LIVE_OBJECT_SUMMARY]
D3D11 WARNING: Live        ID3D11DepthStencilState :      1 [ STATE_CREATION WARNING #422: LIVE_OBJECT_SUMMARY]
D3D11 WARNING: Live          ID3D11RasterizerState :      1 [ STATE_CREATION WARNING #422: LIVE_OBJECT_SUMMARY]
D3D11 WARNING: Live                  ID3D11Sampler :      1 [ STATE_CREATION WARNING #422: LIVE_OBJECT_SUMMARY]
D3D11 WARNING: Live                    ID3D11Query :      1 [ STATE_CREATION WARNING #422: LIVE_OBJECT_SUMMARY]
D3D11 WARNING: Live                 IDXGISwapChain :      1 [ STATE_CREATION WARNING #422: LIVE_OBJECT_SUMMARY]
D3D11 WARNING: Live                ID3D11Texture2D :      1 [ STATE_CREATION WARNING #422: LIVE_OBJECT_SUMMARY]

I am running out of hypotheses to test against (to prove or disprove). If I call releaseAndGetAddressOf() on each of the obects before creating them then everything works out fine - the resizing works and all resources are released ok at the end. The only problem being ID3DDebugInfoQueue access violation when releasing at the end of main. I think it could be heap corruption due to the 'hack' of releasing - supposedly already null objects before creating them. So as you can see I can't do that. I need to understand the root of the problem - which is why 2 of everything are being created. I can't just keep releasing the same object until its free!?! I need to find its dependencies.

I would dearly be supported by your advice on this matter fellow developers.

Do you have a minimal app that reproduces the problem that you can paste the full code to?

If not, make such a minimal app that just creates a window and clears the background and then exits again, and if it works correctly there, add stuff until the problem comes back.

Thanks Erik Rufelt...

I have solved it...

I took your advice and created a minimal app copy of the original, cutting the program down to the production of a resizable window. 'Unfortunately' it worked fine! The entire thing was inlined in a translation unit. I was going to post it here but didn't see the point as it did not reproduce the error. So I tried to keep the structure of the original and started to slowly shave parts of the project off until it worked - thereby revealing the culprit code. But that proved too difficult as I couldn't just unplug certain classes - it would mean a redesign of everything. So then I tried firing up the Graphics Debugger to see if it would display the inner workings of what might be going wrong. It mysteriously failed on the creation of the SwapChain with E_NOINTERFACE. This was a blessing in disguise as it lead me to the very area of the problem. Whilst trying to make that work I found that in my attempt to upgrade from DX11.0 to DX11.1 I was going around upgrading the version suffixes of the DX components namely the SwapChain/Device/Context/Adapter/Factory etc.. Here where I created the Adapter and Factory, in my cross-eyed-ness, I had left out the correct suffixes for the uuidof(...) part. It should have been:


Microsoft::WRL::ComPtr<IDXGIAdapter2> spDxgiAdapter;
HR(spDXGIDevice->GetParent(__uuidof(IDXGIAdapter2), (void**)&spDxgiAdapter));
Microsoft::WRL::ComPtr<IDXGIFactory2> spDxgiFactory;
HR(spDxgiAdapter->GetParent(__uuidof(IDXGIFactory2), (void**)&spDxgiFactory));

Oh man, that created all sorts of havoc. I should have given more info in the beginning then you guys may have picked it up.

Thanks profusely.

This topic is closed to new replies.

Advertisement