Advertisement

Pipeline State Object Emulation

Started by August 27, 2019 12:25 PM
1 comment, last by Jman2 5 years, 5 months ago

Howdy,

Would like some input on a clean method for Emulating the Graphics Pipeline state Object for DX11, so my current render enigne works using handls such that:
 


// Just using blend as example! 
struct BLEND_STATE_DESC
{
	bool                     m_AlphaToCoverageEnable  = false;
	bool                     m_IndependentBlendEnable = false;
	RENDER_TARGET_BLEND_DESC m_RenderTarget[8];
};

// Graphics Device blend functions
class GraphicsDevice
{
	SlotMap<IF3DBlendState> m_BlendStates; //Init calls constructor setting number like max 128

	BlendStateHandle CreateBlendState(const BLEND_DESC* pDesc);
	void DestoryBlendState(BlendStateHandle handle);
	IF3DBlendState* AccessBlendState(const BlendStateHandle& handle); //Custom object
}

struct GRAPHICS_PIPLINE_STATE_DESC
{
	VertexShaderHandle      m_VertexShader;
	PixelShaderHandle       m_PixelShader;
	DomainShaderHandle      m_DomainShader;
	HullShaderHandle        m_HullShader;
	GeometryShaderHandle    m_GeometryShader;
	ComputeShaderHandle     m_GeometryShader;
	BlendStateHandle        m_BlendState;
	RasterizerStateHandle   m_RasterizerState;
	DepthStencilStateHandle m_DepthStencilState;
	InputLayoutHandle       m_InputLayout;

	TOPOLOGY                m_TopologyType = TOPOLOGY_TRIANGLELIST;
	Uint32                  m_RenderTargetCount = 0; //DX12 Only
	SURFACE_FORMAT          m_RenderTargetFormats[8] = {}; //DX12 only
	SURFACE_FORMAT          m_DepthFormat = SURFACE_FORMAT::FORMAT_UNKNOWN; //DX12 Only
	MULTISAMPLING           m_SampleDesc;
	Uint32                  m_SampleMask = 0xFFFFFFFF;
};

Okay so this would work, as the Blend object stores the desc for DX12 and a native ptr (it’s actually a Uint32 to be cast for GL, DX, Vulkan etc) however the issue comes with the deletion.
I would be nice for the Pipeline state object to be like DX12 where you can just call release or in my case m_Device->DesotryPipelineState(PipelineStateHandle); etc.

However, internally for DX11 each state is stored as a native pointer and would need cleaning up, again this is fine if every blend state was unique but there not, in have gone the way of DXTK with common states:


class CommonStates
{
private:
	static GraphicsDevice* m_GraphicsDevice;

	// Blend states.
	static BlendStateHandle m_Opaque;
	static BlendStateHandle m_AlphaBlend;
	static BlendStateHandle m_Additive;
	static BlendStateHandle m_NonPremultiplied;

	// Depth stencil states.
	static DepthStencilStateHandle m_DepthNone;
	static DepthStencilStateHandle m_DepthDefault;
	static DepthStencilStateHandle m_DepthRead;

	// Rasterizer states.
	static RasterizerStateHandle m_CullNone;
	static RasterizerStateHandle m_CullClockwise;
	static RasterizerStateHandle m_CullCounterClockwise;
	static RasterizerStateHandle m_Wireframe;

	// Sampler states.
	static SamplerStateHandle m_PointWrap;
	static SamplerStateHandle m_PointClamp;
	static SamplerStateHandle m_LinearWrap;
	static SamplerStateHandle m_LinearClamp;
	static SamplerStateHandle m_AnisotropicWrap;
	static SamplerStateHandle m_AnisotropicClamp;

public:
	static void Initalize(const GraphicsDevice* device);
	static void ShutDown();

	// Blend states.
	static BlendStateHandle Opaque();
	static BlendStateHandle AlphaBlend();
	static BlendStateHandle Additive();
	static BlendStateHandle NonPremultiplied();
	 
	// Depth stencil states.
	static DepthStencilStateHandle DepthNone();
	static DepthStencilStateHandle DepthDefault();
	static DepthStencilStateHandle DepthRead();
	 
	// Rasterizer states.
	static RasterizerStateHandle CullNone();
	static RasterizerStateHandle CullClockwise();
	static RasterizerStateHandle CullCounterClockwise();
	static RasterizerStateHandle Wireframe();
	 
	// Sampler states.
	static SamplerStateHandle PointWrap();
	static SamplerStateHandle PointClamp();
	static SamplerStateHandle LinearWrap();
	static SamplerStateHandle LinearClamp();
	static SamplerStateHandle AnisotropicWrap();
	static SamplerStateHandle AnisotropicClamp();

};

So as you can imagine when PipelineState destroy is called it would need to figure out whether to destroy or not, this is easy in dx12 but more troublesome in dx11. You could suggest using reference counting but i feel that defeats the point in handles which are suppose to be simple objects. Forceing user to store all there data manually and releasing them is another option but feels a bit unclean.

Would appreciate any perspectives on the subject!
Thanks,

Just a follow up, the most likely solution is to store descs for the pipeline state and not handles (except for the shaders) then in the graphics device grab a hash of the states such as blend, raster etc. Then store a hash table with the handles into the slot map that way when we go to create a state we can check if it exists and just share it. And because we know we won’t have many just reserve memory chuck’s in the slot maps for each state and leave them persistent until the app closes. This makes the most sense as you should front load all the pipeline states anyway.

This topic is closed to new replies.

Advertisement