0
\$\begingroup\$

I've recently decided to get rid of pretty much all of the raw pointers from my Direct3D code, and I ran into a problem with using ComPtr<T> template with multiple render targets.

Microsoft suggests using ComPtr<T> for D3D instead of unique_ptr<T> or shared_ptr<T>. However even their example shows how to use it with OMSetRenderTargets, but I couldn't really find anything how to use it when you have to bind an array of managed objects.

Here's some code of my current solution:

class Texture{
public:
    void Initialize(const Bitmap &bitmap){ /* ... */}

    ID3D11ShaderResourceView* GetShaderResourceView() const { return this->m_pResourceView; }
    ID3D11RenderTargetView* GetRenderTargetView() const { return this->m_pTargetView; }
    ID3D11Resource* GetTextureResource() const { return this->m_pTexture; }

    ID3D11Texture2D* GetTexture2D() const { return static_cast<ID3D11Texture2D*>(this->m_pTexture); }

private:
    ID3D11ShaderResourceView * m_pResourceView;
    ID3D11RenderTargetView * m_pTargetView;
    ID3D11Resource * m_pTexture;
}

class Renderer{
public:
    void Initialize(const Window & targetWindow){ /* ... */ }

    void SetDepthStencilView(ID3D11DepthStencilView* pDepthStencilView = nullptr){
        n = n < RENDER_TARGET_MAX ? n : RENDER_TARGET_MAX;
        if (!n && pRenderTargetView == nullptr) {
            m_renderTargetViews[0] = m_myRenderTargetView;
        } else {
            m_renderTargetViews[n] = pRenderTargetView;
        }
    }

    void SetRenderTargetView(ID3D11RenderTargetView* pRenderTargetView = nullptr, size_t n = 0){
        if (pDepthStencilview == nullptr) {
            m_depthStencilView = m_myDepthStencilView;
        }
        else {
            m_depthStencilView = pDepthStencilview;
        }
    }

    void ApplyRenderTargetView(size_t count = 1){
        m_renderTargetViewCount = count < RENDER_TARGET_MAX ? count : RENDER_TARGET_MAX;
        m_deviceContext->OMSetRenderTargets(m_renderTargetViewCount, m_renderTargetViews, m_depthStencilView);
    }

private:
    ID3D11Device* m_device; // device context, swap chain, raster state, etc ...
    ID3D11RenderTargetView* m_renderTargetViews[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT], *m_myRenderTargetView; // This is the screen as a default
    size_t m_renderTargetViewCount;
    // depth stencil buffer, etc ...
}


void some_use_case(Renderer & render){
    Texture colorMap;
    Texture normalMap;
    Texture positionMap;

    render.SetRenderTargetView(colorMap.GetRenderTargetView(), 0);
    render.SetRenderTargetView(normalMap.GetRenderTargetView(), 1);
    render.SetRenderTargetView(positionMap.GetRenderTargetView(), 2);

    // ... Render geometry
    // ... Render posteffects
}

Keep tracking and releasing all of the resources are way too tedious, and It's reasonable to introduce some smart pointer solution here. How could I replace the pointer definition, and how could I bind it m_renderTargetViews to OMSetRenderTargets?

\$\endgroup\$
0
\$\begingroup\$

For single item arrays, you can easily use GetAddressOf() on a ComPtr, but for multiple item arrays you just create it on the stack:

Microsoft::WRL::ComPtr<ID3D11RenderTargetView> m_renderTargetViews[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
Microsoft::WRL::ComPtr<ID3D1DepthStencilView> m_depthStencilView;

….

 m_deviceContext->OMSetRenderTargets(1, m_renderTargetViews[0].GetAddressOf(),
    m_depthStencilView.Get());

...

ID3D11RenderTargetView* rtv[2] = { m_renderTargetViews[0].Get(),
    m_renderTargetViews[1].Get() };
m_deviceContext->OMSetRenderTargets(__countof(rtv), rtv,
     m_depthStencilView.Get());

See ComPtr.

\$\endgroup\$

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.