For DX11 I wrote RAII wrappers like this:
class OmBlendState
{
public:
//blendFactor == nullptr => DX will use{ 1, 1, 1, 1 }
OmBlendState(const Microsoft::WRL::ComPtr<ID3D11DeviceContext>& context, ID3D11BlendState* blendState, const float* blendFactor = nullptr, unsigned sampleMask = 0xFFFFFFFF);
~OmBlendState();
private:
const Microsoft::WRL::ComPtr<ID3D11DeviceContext>& m_context;
};
OmBlendState::OmBlendState(const Microsoft::WRL::ComPtr<ID3D11DeviceContext>& context, ID3D11BlendState* blendState, const float* blendFactor /*=nullptr*/, unsigned sampleMask /*=0xFFFFFFFF*/)
: m_context{context}
{
context->OMSetBlendState(blendState, blendFactor, sampleMask);
}
OmBlendState::~OmBlendState()
{
m_context->OMSetBlendState(nullptr, nullptr, 0xFFFFFFFF);
}
Usage:
void TranspPass::Render()
{
...
OmBlendState bs{ m_context, m_omAlphaBlendState.Get() };
...
m_context->DrawIndexedInstanced(iaBuff.GetIndexCount(), static_cast<UINT>(instData.size()), 0, 0, 0);
}
Wrappers upon other states have different interface, for example RT:
class OmRenderTargets
{
public:
//Max RTS - 8 (DX11 && DX12)
OmRenderTargets(const Microsoft::WRL::ComPtr<ID3D11DeviceContext>& context, ID3D11DepthStencilView* pDepthStencilView);
OmRenderTargets(const Microsoft::WRL::ComPtr<ID3D11DeviceContext>& context, ID3D11RenderTargetView* rtv0, ID3D11DepthStencilView* pDepthStencilView);
OmRenderTargets(const Microsoft::WRL::ComPtr<ID3D11DeviceContext>& context, ID3D11RenderTargetView* rtv0, ID3D11RenderTargetView* rtv1, ID3D11DepthStencilView* pDepthStencilView);
OmRenderTargets(const Microsoft::WRL::ComPtr<ID3D11DeviceContext>& context, ID3D11RenderTargetView* rtv0, ID3D11RenderTargetView* rtv1, ID3D11RenderTargetView* rtv2, ID3D11DepthStencilView* pDepthStencilView);
OmRenderTargets(const Microsoft::WRL::ComPtr<ID3D11DeviceContext>& context, ID3D11RenderTargetView* rtv0, ID3D11RenderTargetView* rtv1, ID3D11RenderTargetView* rtv2, ID3D11RenderTargetView* rtv3, ID3D11DepthStencilView* pDepthStencilView);
OmRenderTargets(const Microsoft::WRL::ComPtr<ID3D11DeviceContext>& context, ID3D11RenderTargetView* rtv0, ID3D11RenderTargetView* rtv1, ID3D11RenderTargetView* rtv2, ID3D11RenderTargetView* rtv3, ID3D11RenderTargetView* rtv4, ID3D11DepthStencilView* pDepthStencilView);
OmRenderTargets(const Microsoft::WRL::ComPtr<ID3D11DeviceContext>& context, ID3D11RenderTargetView* rtv0, ID3D11RenderTargetView* rtv1, ID3D11RenderTargetView* rtv2, ID3D11RenderTargetView* rtv3, ID3D11RenderTargetView* rtv4, ID3D11RenderTargetView* rtv5, ID3D11DepthStencilView* pDepthStencilView);
OmRenderTargets(const Microsoft::WRL::ComPtr<ID3D11DeviceContext>& context, ID3D11RenderTargetView* rtv0, ID3D11RenderTargetView* rtv1, ID3D11RenderTargetView* rtv2, ID3D11RenderTargetView* rtv3, ID3D11RenderTargetView* rtv4, ID3D11RenderTargetView* rtv5, ID3D11RenderTargetView* rtv6, ID3D11DepthStencilView* pDepthStencilView);
OmRenderTargets(const Microsoft::WRL::ComPtr<ID3D11DeviceContext>& context, ID3D11RenderTargetView* rtv0, ID3D11RenderTargetView* rtv1, ID3D11RenderTargetView* rtv2, ID3D11RenderTargetView* rtv3, ID3D11RenderTargetView* rtv4, ID3D11RenderTargetView* rtv5, ID3D11RenderTargetView* rtv6, ID3D11RenderTargetView* rtv7, ID3D11DepthStencilView* pDepthStencilView);
~OmRenderTargets();
private:
const Microsoft::WRL::ComPtr<ID3D11DeviceContext>& m_context;
};
I do not use RAII wrappers upon Vertex Shader, Pixel Shader, IA, because it will be rewritten on next rendering stage.
But for GS/CS I always do.
So after each Rendering stage, pipeline is pretty clean and there is no need to reset states I did not touch.
This solution is better than having some "Reset all states" object.
As a bonus - Exception safe :)