1
\$\begingroup\$

I have successfully used _com_ptr_t with the ID3D11Device and IDXGISwapChain but when applying the same reasoning to the RenderTargetView and DepthStencilView, the function m_spD3DImmediateContext->OMSetRenderTargets(...) sets the m_spRenderTargetView smart COM pointer to null! Then, subsequent draw calls fail on ClearRenderTargetView and ClearDepthStencilView.

Is it because I am passing the smart pointer incorrectly?

HR(m_spD3DDevice->CreateRenderTargetView(pBackBuffer, 0, &m_spRenderTargetView));
...
HR(m_spD3DDevice->CreateTexture2D(&stDepthStencilDesc, 0, &m_spDepthStencilBuffer));
...
m_spD3DImmediateContext->OMSetRenderTargets(1, &m_spRenderTargetView, m_spDepthStencilView);
assert(m_spRenderTargetView); // <=== FAIL

I think the smart pointer overloads the operator& so that it returns an Interface** (see Extractors in _com_ptr_t class).

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

The issue you are hitting is that OMSetRenderTargets does not take a pointer to the RenderTargetView object. It takes a pointer to an array of pointers to RenderTargetView objects to support Multiple Render Target (MRT) rendering configurations.

void OMSetRenderTargets(UINT NumViews, ID3D11RenderTargetView *const *ppRenderTargetViews,
    ID3D11DepthStencilView *pDepthStencilView );

The default operator& overload for _com_ptr_t and Microsoft::WRL::ComPtr assume you are using the pattern like in CreateRenderTarget so it Releases the object and sets the pointer to null before returning the address of the contained pointer. This avoids a leak. Note the older ATL CComPtr's operator& did not Release and instead asserted the pointer to be null.

HR(m_spD3DDevice->CreateRenderTargetView(pBackBuffer, 0, &m_spRenderTargetView));

With Microsoft::WRL::ComPtr, you can use the explicit GetAddressOf() or ReleaseAndGetAddressOf() methods to get the 'right' behavior. This is why generally ComPtr (or the older ATL CComPtr) is preferred to _com_ptr_t for Direct3D programming.

HR(m_spD3DDevice->CreateRenderTargetView(pBackBuffer, 0, m_spRenderTargetView.ReleaseAndGetAddressOf()));
...
HR(m_spD3DDevice->CreateTexture2D(&stDepthStencilDesc, 0, m_spDepthStencilBuffer.ReleaseAndGetAddressOf()));
...
m_spD3DImmediateContext->OMSetRenderTargets(1, m_spRenderTargetView.GetAddressOf(), m_spDepthStencilView);

With _com_ptr_t you need to use something like:

ID3D11RenderTargetView* rtv = m_spRenderTargetView.GetInterfacePtr();
m_spD3DImmediateContext->OMSetRenderTargets(1, &rtv, m_spDepthStencilView);
\$\endgroup\$
4
  • \$\begingroup\$ In addition here are some links Smart COM Pointers (Modern C++)" and Wiki ATL You mentioned Microsoft::WRL::ComPtr but I dont know how to include the neccassary headers to instantiate this. I downloaded the WRL Class Library extension to VS2012 but I still can't '#include <WRL*anything*>' \$\endgroup\$ Commented Aug 13, 2014 at 14:08
  • \$\begingroup\$ With VS 2012 or VS 2013 you just use #include <wrl/client.h>. For VS 2010, you can use the Windows 8.x SDK with the integration instructions. Those instructions omit the 'include\winrt' path unfortunately which you need for Microsoft::WRL::ComPtr. You can get working .props files from my blog for the Windows 8.1 SDK. \$\endgroup\$ Commented Aug 13, 2014 at 18:04
  • \$\begingroup\$ Note that Microsoft::WRL::ComPtr works fine in Windows Store apps, Windows Phone apps, Win32 desktop apps for Windows Vista or later, and Xbox One apps. I use it extensively in DirectX Tool Kit. \$\endgroup\$ Commented Aug 13, 2014 at 18:08
  • \$\begingroup\$ I've got it. It was the fact that I was using DirectXSDK directory and not the Windows Kits 8.0 directory. \$\endgroup\$ Commented Aug 13, 2014 at 20:27

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.