As an example, one of the interfaces needed while setting up the render pipeline is the DepthStencilView ( ID3D11DepthStencilView ). It requires a DXGI_FORMAT and there are only five supported formats for creating a ID3D11DepthStencilView interface.
I could write something like:
Code: Select all
// Helper trait to determine if format is supported as a depth buffer format
template<DXGI::Format _format> struct is_supported_depth_buffer_view_format : std::false_type {};
template<> struct is_supported_depth_buffer_view_format<DXGI::Format::Unknown> : std::true_type {};
template<> struct is_supported_depth_buffer_view_format<DXGI::Format::D16_UNorm> : std::true_type {};
template<> struct is_supported_depth_buffer_view_format<DXGI::Format::D24_UNorm_S8_UInt> : std::true_type {};
template<> struct is_supported_depth_buffer_view_format<DXGI::Format::D32_Float> : std::true_type {};
template<> struct is_supported_depth_buffer_view_format<DXGI::Format::D32_Float_S8X24_UInt> : std::true_type {};
// Syntactic sugar else: is_supported_depth_buffer_view<_format>::value
template<DXGI::Format _format>
constexpr bool is_supported_depth_buffer_view_format_v =
is_supported_depth_buffer_view_format<_format>::value;
// Default all formats as not supported
template<typename T, DXGI::Format _format>
struct is_supported_format : std::false_type {};
// Specialize on T using previously defined support traits for type T
template<DXGI::Format _format> struct is_supported_format<DepthStencilView, _format> :
std::conditional_t<is_supported_depth_buffer_view_format_v<_format>, std::true_type, std::false_type> {};
// Syntactic sugar else: is_supported_format<T, _format>::value
template<typename T, DXGI::Format _format>
constexpr bool is_supported_format_v = is_supported_format<T, _format>::value;
The is_supported_depth_buffer_view struct deals directly with the DepthStencilView so only takes the format enum as it's template parameter. It is defined as false by default and true for each of the supported types by inheritance. If I pass in a DXGI::Format::Unknown as the parameter, the is_supported_depth_buffer_view<DXGI::Format::Unknown> struct inherits from std::true_type and inherits the static constexpr bool value of true.
So, how to use this. You have to create a DepthStencilViewDesc struct to pass to the DepthStencilView constructor. So the DepthStencilViewDesc will be templated and the template variables can be check at compile time and will cause a compile time error if the incorrect format is passed in.
Code: Select all
template<DXGI::Format _format>
struct DepthStencilViewDesc
{
static_assert( is_supported_depth_stencil_view_format_v<_format>,
"Invalid format used for DepthStencilViewDesc, supported DXGI::Format formats:\n"
"Unknown, D16_UNorm, D24_UNorm_S8_UInt, D32_Float and D32_Float_S8X24_UInt" );
DepthStencilViewDesc()=default;
DepthStencilViewDesc( const D3D11_DEPTH_STENCIL_VIEW_DESC& _source );
operator D3D11_DEPTH_STENCIL_VIEW_DESC() const;
DXGI::Format Format;
DSVDimension ViewDimension;
DSVFlag Flags;
union
{
Tex1DDSV Texture1D;
Tex1DArrayDSV Texture1DArray;
Tex2DDSV Texture2D;
Tex2DArrayDSV Texture2DArray;
Tex2DMultisampleDSV Texture2DMS;
Tex2DMultisampleArrayDSV Texture2DMSArray;
};
};
I'm sure I'll be able to use the is_supported_format version at some point, but I haven't gone completely generic programming yet. I want to be able to go as generic as I can and only rely on the type system. There are features, formats and other aspects that are only available using later versions of Direct3D, but where possible I'd like to be able to reuse code and allow for static polymorphism ( as shown in the traits code above ).
I still have a few things to learn when it comes to template meta-programming, but I think I'm on the right track. If anyone is interested, I am mostly learning from reading through the standard library and stackoverflow. There are a few basic tutorials on YouTube, there might be more advanced ones also, but I haven't looked yet.