Files
UnrealEngine/Engine/Source/Runtime/RenderCore/Public/RHIStaticStates.h
2025-05-18 13:04:45 +08:00

411 lines
16 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
RHIStaticStates.h: RHI static state template definition.
=============================================================================*/
#pragma once
#include "Stats/Stats.h"
#include "Async/TaskGraphInterfaces.h"
#include "Containers/StaticArray.h"
#include "RHI.h"
#include "RenderResource.h"
#include "Misc/ScopedEvent.h"
/**
* Helper task to initialize a static resource on the render thread.
*/
class FInitStaticResourceRenderThreadTask
{
void (*DoConstruct)();
FScopedEvent& Event;
public:
FInitStaticResourceRenderThreadTask(void (*InDoConstruct)(), FScopedEvent& InEvent)
: DoConstruct(InDoConstruct)
, Event(InEvent)
{
}
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FInitStaticResourceRenderThreadTask, STATGROUP_TaskGraphTasks);
}
ENamedThreads::Type GetDesiredThread()
{
return ENamedThreads::GetRenderThread_Local();
}
static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::FireAndForget; }
void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
{
DoConstruct();
Event.Trigger();
}
};
/**
* The base class of the static RHI state classes.
*/
template<typename InitializerType,typename RHIRefType,typename RHIParamRefType>
class TStaticStateRHI
{
public:
static RHIParamRefType GetRHI()
{
checkSlow(StaticResource.StateRHI);
return StaticResource.StateRHI;
};
private:
/** A resource which manages the RHI resource. */
class FStaticStateResource : public FRenderResource
{
public:
RHIRefType StateRHI;
FStaticStateResource()
{
if (GIsRHIInitialized && GRHISupportsRHIThread)
{
StateRHI = InitializerType::CreateRHI();
}
else
{
BeginInitResource(this);
}
}
// FRenderResource interface.
virtual void InitRHI(FRHICommandListBase& RHICmdList) override
{
check(!GIsRHIInitialized || !GRHISupportsRHIThread);
StateRHI = InitializerType::CreateRHI();
}
virtual void ReleaseRHI() override final
{
check(!GIsRHIInitialized || !GRHISupportsRHIThread);
StateRHI.SafeRelease();
}
virtual void ReleaseResource() override final
{
FRenderResource::ReleaseResource();
}
~FStaticStateResource()
{
check(!GIsRHIInitialized || !GRHISupportsRHIThread);
ReleaseResource();
}
};
static FStaticStateResource StaticResource;
};
template<typename InitializerType, typename RHIRefType, typename RHIParamRefType>
typename TStaticStateRHI<InitializerType, RHIRefType, RHIParamRefType>::FStaticStateResource TStaticStateRHI<InitializerType, RHIRefType, RHIParamRefType>::StaticResource = TStaticStateRHI<InitializerType, RHIRefType, RHIParamRefType>::FStaticStateResource();
/**
* A static RHI sampler state resource.
* TStaticSamplerStateRHI<...>::GetStaticState() will return a FSamplerStateRHIRef to a sampler state with the desired settings.
* Should only be used from the rendering thread.
*/
template<ESamplerFilter Filter=SF_Point,
ESamplerAddressMode AddressU=AM_Clamp,
ESamplerAddressMode AddressV=AM_Clamp,
ESamplerAddressMode AddressW=AM_Clamp,
int32 MipBias = 0,
// Note: setting to a different value than GSystemSettings.MaxAnisotropy is only supported in D3D11 (is that still true?)
// A value of 0 will use GSystemSettings.MaxAnisotropy
int32 MaxAnisotropy = 1,
uint32 BorderColor = 0,
/** Only supported in D3D11 */
ESamplerCompareFunction SamplerComparisonFunction=SCF_Never>
class TStaticSamplerState : public TStaticStateRHI<TStaticSamplerState<Filter,AddressU,AddressV,AddressW,MipBias,MaxAnisotropy,BorderColor,SamplerComparisonFunction>,FSamplerStateRHIRef, FRHISamplerState*>
{
public:
static FSamplerStateRHIRef CreateRHI()
{
FSamplerStateInitializerRHI Initializer( Filter, AddressU, AddressV, AddressW, MipBias, MaxAnisotropy, 0, FLT_MAX, BorderColor, SamplerComparisonFunction );
return RHICreateSamplerState(Initializer);
}
};
/**
* A static RHI rasterizer state resource.
* TStaticRasterizerStateRHI<...>::GetStaticState() will return a FRasterizerStateRHIRef to a rasterizer state with the desired
* settings.
* Should only be used from the rendering thread.
*/
template<ERasterizerFillMode FillMode = FM_Solid, ERasterizerCullMode CullMode = CM_None, ERasterizerDepthClipMode DepthClipMode = ERasterizerDepthClipMode::DepthClip, bool bEnableMSAA = true>
class TStaticRasterizerState : public TStaticStateRHI<TStaticRasterizerState<FillMode, CullMode, DepthClipMode, bEnableMSAA>, FRasterizerStateRHIRef, FRHIRasterizerState*>
{
public:
FORCEINLINE_DEBUGGABLE static FRasterizerStateRHIRef CreateRHI()
{
const FRasterizerStateInitializerRHI Initializer(FillMode, CullMode, 0.0f, 0.0f, DepthClipMode, bEnableMSAA);
return RHICreateRasterizerState(Initializer);
}
};
/** Given a fill and cull mode, returns a static rasterizer state. */
template<bool bEnableMSAA>
FORCEINLINE_DEBUGGABLE FRHIRasterizerState* GetStaticRasterizerState(ERasterizerFillMode FillMode,ERasterizerCullMode CullMode)
{
constexpr ERasterizerDepthClipMode DepthClipMode = ERasterizerDepthClipMode::DepthClip;
switch(FillMode)
{
default:
case FM_Solid:
switch(CullMode)
{
default:
case CM_CW: return TStaticRasterizerState<FM_Solid,CM_CW , DepthClipMode, bEnableMSAA>::GetRHI();
case CM_CCW: return TStaticRasterizerState<FM_Solid,CM_CCW , DepthClipMode, bEnableMSAA>::GetRHI();
case CM_None: return TStaticRasterizerState<FM_Solid,CM_None, DepthClipMode, bEnableMSAA>::GetRHI();
};
break;
case FM_Wireframe:
switch(CullMode)
{
default:
case CM_CW: return TStaticRasterizerState<FM_Wireframe,CM_CW , DepthClipMode, bEnableMSAA>::GetRHI();
case CM_CCW: return TStaticRasterizerState<FM_Wireframe,CM_CCW , DepthClipMode, bEnableMSAA>::GetRHI();
case CM_None: return TStaticRasterizerState<FM_Wireframe,CM_None, DepthClipMode, bEnableMSAA>::GetRHI();
};
break;
case FM_Point:
switch(CullMode)
{
default:
case CM_CW: return TStaticRasterizerState<FM_Point,CM_CW , DepthClipMode, bEnableMSAA>::GetRHI();
case CM_CCW: return TStaticRasterizerState<FM_Point,CM_CCW , DepthClipMode, bEnableMSAA>::GetRHI();
case CM_None: return TStaticRasterizerState<FM_Point,CM_None, DepthClipMode, bEnableMSAA>::GetRHI();
};
break;
}
}
/**
* A static RHI stencil state resource.
* TStaticStencilStateRHI<...>::GetStaticState() will return a FDepthStencilStateRHIRef to a stencil state with the desired
* settings.
* Should only be used from the rendering thread.
*/
template<
bool bEnableDepthWrite = true,
ECompareFunction DepthTest = CF_DepthNearOrEqual,
bool bEnableFrontFaceStencil = false,
ECompareFunction FrontFaceStencilTest = CF_Always,
EStencilOp FrontFaceStencilFailStencilOp = SO_Keep,
EStencilOp FrontFaceDepthFailStencilOp = SO_Keep,
EStencilOp FrontFacePassStencilOp = SO_Keep,
bool bEnableBackFaceStencil = false,
ECompareFunction BackFaceStencilTest = CF_Always,
EStencilOp BackFaceStencilFailStencilOp = SO_Keep,
EStencilOp BackFaceDepthFailStencilOp = SO_Keep,
EStencilOp BackFacePassStencilOp = SO_Keep,
uint8 StencilReadMask = 0xFF,
uint8 StencilWriteMask = 0xFF
>
class TStaticDepthStencilState : public TStaticStateRHI<
TStaticDepthStencilState<
bEnableDepthWrite,
DepthTest,
bEnableFrontFaceStencil,
FrontFaceStencilTest,
FrontFaceStencilFailStencilOp,
FrontFaceDepthFailStencilOp,
FrontFacePassStencilOp,
bEnableBackFaceStencil,
BackFaceStencilTest,
BackFaceStencilFailStencilOp,
BackFaceDepthFailStencilOp,
BackFacePassStencilOp,
StencilReadMask,
StencilWriteMask
>,
FDepthStencilStateRHIRef,
FRHIDepthStencilState*
>
{
public:
static FDepthStencilStateRHIRef CreateRHI()
{
FDepthStencilStateInitializerRHI Initializer(
bEnableDepthWrite,
DepthTest,
bEnableFrontFaceStencil,
FrontFaceStencilTest,
FrontFaceStencilFailStencilOp,
FrontFaceDepthFailStencilOp,
FrontFacePassStencilOp,
bEnableBackFaceStencil,
BackFaceStencilTest,
BackFaceStencilFailStencilOp,
BackFaceDepthFailStencilOp,
BackFacePassStencilOp,
StencilReadMask,
StencilWriteMask);
return RHICreateDepthStencilState(Initializer);
}
};
/**
* A static RHI blend state resource.
* TStaticBlendStateRHI<...>::GetStaticState() will return a FBlendStateRHIRef to a blend state with the desired settings.
* Should only be used from the rendering thread.
*
* Alpha blending happens on GPU's as:
* FinalColor.rgb = SourceColor * ColorSrcBlend (ColorBlendOp) DestColor * ColorDestBlend;
* if (BlendState->bSeparateAlphaBlendEnable)
* FinalColor.a = SourceAlpha * AlphaSrcBlend (AlphaBlendOp) DestAlpha * AlphaDestBlend;
* else
* Alpha blended the same way as rgb
*
* Where source is the color coming from the pixel shader, and target is the color in the render target.
*
* So for example, TStaticBlendState<BO_Add,BF_SourceAlpha,BF_InverseSourceAlpha,BO_Add,BF_Zero,BF_One> produces:
* FinalColor.rgb = SourceColor * SourceAlpha + DestColor * (1 - SourceAlpha);
* FinalColor.a = SourceAlpha * 0 + DestAlpha * 1;
*/
template<
EColorWriteMask RT0ColorWriteMask = CW_RGBA,
EBlendOperation RT0ColorBlendOp = BO_Add,
EBlendFactor RT0ColorSrcBlend = BF_One,
EBlendFactor RT0ColorDestBlend = BF_Zero,
EBlendOperation RT0AlphaBlendOp = BO_Add,
EBlendFactor RT0AlphaSrcBlend = BF_One,
EBlendFactor RT0AlphaDestBlend = BF_Zero,
EColorWriteMask RT1ColorWriteMask = CW_RGBA,
EBlendOperation RT1ColorBlendOp = BO_Add,
EBlendFactor RT1ColorSrcBlend = BF_One,
EBlendFactor RT1ColorDestBlend = BF_Zero,
EBlendOperation RT1AlphaBlendOp = BO_Add,
EBlendFactor RT1AlphaSrcBlend = BF_One,
EBlendFactor RT1AlphaDestBlend = BF_Zero,
EColorWriteMask RT2ColorWriteMask = CW_RGBA,
EBlendOperation RT2ColorBlendOp = BO_Add,
EBlendFactor RT2ColorSrcBlend = BF_One,
EBlendFactor RT2ColorDestBlend = BF_Zero,
EBlendOperation RT2AlphaBlendOp = BO_Add,
EBlendFactor RT2AlphaSrcBlend = BF_One,
EBlendFactor RT2AlphaDestBlend = BF_Zero,
EColorWriteMask RT3ColorWriteMask = CW_RGBA,
EBlendOperation RT3ColorBlendOp = BO_Add,
EBlendFactor RT3ColorSrcBlend = BF_One,
EBlendFactor RT3ColorDestBlend = BF_Zero,
EBlendOperation RT3AlphaBlendOp = BO_Add,
EBlendFactor RT3AlphaSrcBlend = BF_One,
EBlendFactor RT3AlphaDestBlend = BF_Zero,
EColorWriteMask RT4ColorWriteMask = CW_RGBA,
EBlendOperation RT4ColorBlendOp = BO_Add,
EBlendFactor RT4ColorSrcBlend = BF_One,
EBlendFactor RT4ColorDestBlend = BF_Zero,
EBlendOperation RT4AlphaBlendOp = BO_Add,
EBlendFactor RT4AlphaSrcBlend = BF_One,
EBlendFactor RT4AlphaDestBlend = BF_Zero,
EColorWriteMask RT5ColorWriteMask = CW_RGBA,
EBlendOperation RT5ColorBlendOp = BO_Add,
EBlendFactor RT5ColorSrcBlend = BF_One,
EBlendFactor RT5ColorDestBlend = BF_Zero,
EBlendOperation RT5AlphaBlendOp = BO_Add,
EBlendFactor RT5AlphaSrcBlend = BF_One,
EBlendFactor RT5AlphaDestBlend = BF_Zero,
EColorWriteMask RT6ColorWriteMask = CW_RGBA,
EBlendOperation RT6ColorBlendOp = BO_Add,
EBlendFactor RT6ColorSrcBlend = BF_One,
EBlendFactor RT6ColorDestBlend = BF_Zero,
EBlendOperation RT6AlphaBlendOp = BO_Add,
EBlendFactor RT6AlphaSrcBlend = BF_One,
EBlendFactor RT6AlphaDestBlend = BF_Zero,
EColorWriteMask RT7ColorWriteMask = CW_RGBA,
EBlendOperation RT7ColorBlendOp = BO_Add,
EBlendFactor RT7ColorSrcBlend = BF_One,
EBlendFactor RT7ColorDestBlend = BF_Zero,
EBlendOperation RT7AlphaBlendOp = BO_Add,
EBlendFactor RT7AlphaSrcBlend = BF_One,
EBlendFactor RT7AlphaDestBlend = BF_Zero,
bool bUseAlphaToCoverage = false
>
class TStaticBlendState : public TStaticStateRHI<
TStaticBlendState<
RT0ColorWriteMask,RT0ColorBlendOp,RT0ColorSrcBlend,RT0ColorDestBlend,RT0AlphaBlendOp,RT0AlphaSrcBlend,RT0AlphaDestBlend,
RT1ColorWriteMask,RT1ColorBlendOp,RT1ColorSrcBlend,RT1ColorDestBlend,RT1AlphaBlendOp,RT1AlphaSrcBlend,RT1AlphaDestBlend,
RT2ColorWriteMask,RT2ColorBlendOp,RT2ColorSrcBlend,RT2ColorDestBlend,RT2AlphaBlendOp,RT2AlphaSrcBlend,RT2AlphaDestBlend,
RT3ColorWriteMask,RT3ColorBlendOp,RT3ColorSrcBlend,RT3ColorDestBlend,RT3AlphaBlendOp,RT3AlphaSrcBlend,RT3AlphaDestBlend,
RT4ColorWriteMask,RT4ColorBlendOp,RT4ColorSrcBlend,RT4ColorDestBlend,RT4AlphaBlendOp,RT4AlphaSrcBlend,RT4AlphaDestBlend,
RT5ColorWriteMask,RT5ColorBlendOp,RT5ColorSrcBlend,RT5ColorDestBlend,RT5AlphaBlendOp,RT5AlphaSrcBlend,RT5AlphaDestBlend,
RT6ColorWriteMask,RT6ColorBlendOp,RT6ColorSrcBlend,RT6ColorDestBlend,RT6AlphaBlendOp,RT6AlphaSrcBlend,RT6AlphaDestBlend,
RT7ColorWriteMask,RT7ColorBlendOp,RT7ColorSrcBlend,RT7ColorDestBlend,RT7AlphaBlendOp,RT7AlphaSrcBlend,RT7AlphaDestBlend,
bUseAlphaToCoverage
>,
FBlendStateRHIRef,
FRHIBlendState*
>
{
public:
static FBlendStateRHIRef CreateRHI()
{
TStaticArray<FBlendStateInitializerRHI::FRenderTarget,8> RenderTargetBlendStates;
RenderTargetBlendStates[0] = FBlendStateInitializerRHI::FRenderTarget(RT0ColorBlendOp,RT0ColorSrcBlend,RT0ColorDestBlend,RT0AlphaBlendOp,RT0AlphaSrcBlend,RT0AlphaDestBlend,RT0ColorWriteMask);
RenderTargetBlendStates[1] = FBlendStateInitializerRHI::FRenderTarget(RT1ColorBlendOp,RT1ColorSrcBlend,RT1ColorDestBlend,RT1AlphaBlendOp,RT1AlphaSrcBlend,RT1AlphaDestBlend,RT1ColorWriteMask);
RenderTargetBlendStates[2] = FBlendStateInitializerRHI::FRenderTarget(RT2ColorBlendOp,RT2ColorSrcBlend,RT2ColorDestBlend,RT2AlphaBlendOp,RT2AlphaSrcBlend,RT2AlphaDestBlend,RT2ColorWriteMask);
RenderTargetBlendStates[3] = FBlendStateInitializerRHI::FRenderTarget(RT3ColorBlendOp,RT3ColorSrcBlend,RT3ColorDestBlend,RT3AlphaBlendOp,RT3AlphaSrcBlend,RT3AlphaDestBlend,RT3ColorWriteMask);
RenderTargetBlendStates[4] = FBlendStateInitializerRHI::FRenderTarget(RT4ColorBlendOp,RT4ColorSrcBlend,RT4ColorDestBlend,RT4AlphaBlendOp,RT4AlphaSrcBlend,RT4AlphaDestBlend,RT4ColorWriteMask);
RenderTargetBlendStates[5] = FBlendStateInitializerRHI::FRenderTarget(RT5ColorBlendOp,RT5ColorSrcBlend,RT5ColorDestBlend,RT5AlphaBlendOp,RT5AlphaSrcBlend,RT5AlphaDestBlend,RT5ColorWriteMask);
RenderTargetBlendStates[6] = FBlendStateInitializerRHI::FRenderTarget(RT6ColorBlendOp,RT6ColorSrcBlend,RT6ColorDestBlend,RT6AlphaBlendOp,RT6AlphaSrcBlend,RT6AlphaDestBlend,RT6ColorWriteMask);
RenderTargetBlendStates[7] = FBlendStateInitializerRHI::FRenderTarget(RT7ColorBlendOp,RT7ColorSrcBlend,RT7ColorDestBlend,RT7AlphaBlendOp,RT7AlphaSrcBlend,RT7AlphaDestBlend,RT7ColorWriteMask);
return RHICreateBlendState(FBlendStateInitializerRHI(RenderTargetBlendStates, bUseAlphaToCoverage));
}
};
/**
* A static RHI blend state resource which only allows controlling MRT write masks, for use when only opaque blending is needed.
*/
template<
EColorWriteMask RT0ColorWriteMask = CW_RGBA,
EColorWriteMask RT1ColorWriteMask = CW_RGBA,
EColorWriteMask RT2ColorWriteMask = CW_RGBA,
EColorWriteMask RT3ColorWriteMask = CW_RGBA,
EColorWriteMask RT4ColorWriteMask = CW_RGBA,
EColorWriteMask RT5ColorWriteMask = CW_RGBA,
EColorWriteMask RT6ColorWriteMask = CW_RGBA,
EColorWriteMask RT7ColorWriteMask = CW_RGBA,
bool bUseAlphaToCoverage = false
>
class TStaticBlendStateWriteMask : public TStaticBlendState<
RT0ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT1ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT2ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT3ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT4ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT5ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT6ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT7ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
bUseAlphaToCoverage
>
{
public:
static FBlendStateRHIRef CreateRHI()
{
return TStaticBlendState<
RT0ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT1ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT2ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT3ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT4ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT5ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT6ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
RT7ColorWriteMask,BO_Add,BF_One,BF_Zero,BO_Add,BF_One,BF_Zero,
bUseAlphaToCoverage
>
::CreateRHI();
}
};