Files
UnrealEngine/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11State.cpp
2025-05-18 13:04:45 +08:00

302 lines
13 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
D3D11State.cpp: D3D state implementation.
=============================================================================*/
#include "D3D11State.h"
#include "D3D11RHIPrivate.h"
#include "RHIUtilities.h"
// Cache of Sampler States; we store pointers to both as we don't want the TMap to be artificially
// modifying ref counts if not needed; so we manage that ourselves
static TMap<ID3D11SamplerState*, FD3D11SamplerState*> GSamplerStateCache;
static FCriticalSection GSamplerStateCacheCS;
void EmptyD3DSamplerStateCache()
{
FScopeLock Lock(&GSamplerStateCacheCS);
for (auto Iter = GSamplerStateCache.CreateIterator(); Iter; ++Iter )
{
auto* State = Iter.Value();
// Manually release
State->Release();
}
GSamplerStateCache.Empty();
}
static D3D11_TEXTURE_ADDRESS_MODE TranslateAddressMode(ESamplerAddressMode AddressMode)
{
switch(AddressMode)
{
case AM_Clamp: return D3D11_TEXTURE_ADDRESS_CLAMP;
case AM_Mirror: return D3D11_TEXTURE_ADDRESS_MIRROR;
case AM_Border: return D3D11_TEXTURE_ADDRESS_BORDER;
default: return D3D11_TEXTURE_ADDRESS_WRAP;
};
}
static D3D11_CULL_MODE TranslateCullMode(ERasterizerCullMode CullMode)
{
switch(CullMode)
{
case CM_CW: return D3D11_CULL_BACK;
case CM_CCW: return D3D11_CULL_FRONT;
default: return D3D11_CULL_NONE;
};
}
static D3D11_FILL_MODE TranslateFillMode(ERasterizerFillMode FillMode)
{
switch(FillMode)
{
case FM_Wireframe: return D3D11_FILL_WIREFRAME;
default: return D3D11_FILL_SOLID;
};
}
static D3D11_COMPARISON_FUNC TranslateCompareFunction(ECompareFunction CompareFunction)
{
switch(CompareFunction)
{
case CF_Less: return D3D11_COMPARISON_LESS;
case CF_LessEqual: return D3D11_COMPARISON_LESS_EQUAL;
case CF_Greater: return D3D11_COMPARISON_GREATER;
case CF_GreaterEqual: return D3D11_COMPARISON_GREATER_EQUAL;
case CF_Equal: return D3D11_COMPARISON_EQUAL;
case CF_NotEqual: return D3D11_COMPARISON_NOT_EQUAL;
case CF_Never: return D3D11_COMPARISON_NEVER;
default: return D3D11_COMPARISON_ALWAYS;
};
}
static D3D11_COMPARISON_FUNC TranslateSamplerCompareFunction(ESamplerCompareFunction SamplerComparisonFunction)
{
switch(SamplerComparisonFunction)
{
case SCF_Less: return D3D11_COMPARISON_LESS;
case SCF_Never:
default: return D3D11_COMPARISON_NEVER;
};
}
static D3D11_STENCIL_OP TranslateStencilOp(EStencilOp StencilOp)
{
switch(StencilOp)
{
case SO_Zero: return D3D11_STENCIL_OP_ZERO;
case SO_Replace: return D3D11_STENCIL_OP_REPLACE;
case SO_SaturatedIncrement: return D3D11_STENCIL_OP_INCR_SAT;
case SO_SaturatedDecrement: return D3D11_STENCIL_OP_DECR_SAT;
case SO_Invert: return D3D11_STENCIL_OP_INVERT;
case SO_Increment: return D3D11_STENCIL_OP_INCR;
case SO_Decrement: return D3D11_STENCIL_OP_DECR;
default: return D3D11_STENCIL_OP_KEEP;
};
}
static D3D11_BLEND_OP TranslateBlendOp(EBlendOperation BlendOp)
{
switch(BlendOp)
{
case BO_Subtract: return D3D11_BLEND_OP_SUBTRACT;
case BO_Min: return D3D11_BLEND_OP_MIN;
case BO_Max: return D3D11_BLEND_OP_MAX;
case BO_ReverseSubtract: return D3D11_BLEND_OP_REV_SUBTRACT;
default: return D3D11_BLEND_OP_ADD;
};
}
static D3D11_BLEND TranslateBlendFactor(EBlendFactor BlendFactor)
{
switch(BlendFactor)
{
case BF_One: return D3D11_BLEND_ONE;
case BF_SourceColor: return D3D11_BLEND_SRC_COLOR;
case BF_InverseSourceColor: return D3D11_BLEND_INV_SRC_COLOR;
case BF_SourceAlpha: return D3D11_BLEND_SRC_ALPHA;
case BF_InverseSourceAlpha: return D3D11_BLEND_INV_SRC_ALPHA;
case BF_DestAlpha: return D3D11_BLEND_DEST_ALPHA;
case BF_InverseDestAlpha: return D3D11_BLEND_INV_DEST_ALPHA;
case BF_DestColor: return D3D11_BLEND_DEST_COLOR;
case BF_InverseDestColor: return D3D11_BLEND_INV_DEST_COLOR;
case BF_ConstantBlendFactor: return D3D11_BLEND_BLEND_FACTOR;
case BF_InverseConstantBlendFactor: return D3D11_BLEND_INV_BLEND_FACTOR;
case BF_Source1Color: return D3D11_BLEND_SRC1_COLOR;
case BF_InverseSource1Color: return D3D11_BLEND_INV_SRC1_COLOR;
case BF_Source1Alpha: return D3D11_BLEND_SRC1_ALPHA;
case BF_InverseSource1Alpha: return D3D11_BLEND_INV_SRC1_ALPHA;
default: return D3D11_BLEND_ZERO;
};
}
FSamplerStateRHIRef FD3D11DynamicRHI::RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer)
{
D3D11_SAMPLER_DESC SamplerDesc;
FMemory::Memzero(&SamplerDesc,sizeof(D3D11_SAMPLER_DESC));
SamplerDesc.AddressU = TranslateAddressMode(Initializer.AddressU);
SamplerDesc.AddressV = TranslateAddressMode(Initializer.AddressV);
SamplerDesc.AddressW = TranslateAddressMode(Initializer.AddressW);
SamplerDesc.MipLODBias = Initializer.MipBias;
SamplerDesc.MaxAnisotropy = ComputeAnisotropyRT(Initializer.MaxAnisotropy);
SamplerDesc.MinLOD = Initializer.MinMipLevel;
SamplerDesc.MaxLOD = Initializer.MaxMipLevel;
// Determine whether we should use one of the comparison modes
const bool bComparisonEnabled = Initializer.SamplerComparisonFunction != SCF_Never;
switch(Initializer.Filter)
{
case SF_AnisotropicLinear:
case SF_AnisotropicPoint:
if (SamplerDesc.MaxAnisotropy == 1)
{
SamplerDesc.Filter = bComparisonEnabled ? D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_LINEAR;
}
else
{
// D3D11 doesn't allow using point filtering for mip filter when using anisotropic filtering
SamplerDesc.Filter = bComparisonEnabled ? D3D11_FILTER_COMPARISON_ANISOTROPIC : D3D11_FILTER_ANISOTROPIC;
}
break;
case SF_Trilinear:
SamplerDesc.Filter = bComparisonEnabled ? D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_LINEAR;
break;
case SF_Bilinear:
SamplerDesc.Filter = bComparisonEnabled ? D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT : D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
break;
case SF_Point:
SamplerDesc.Filter = bComparisonEnabled ? D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT : D3D11_FILTER_MIN_MAG_MIP_POINT;
break;
}
const FLinearColor LinearBorderColor = FColor(Initializer.BorderColor);
SamplerDesc.BorderColor[0] = LinearBorderColor.R;
SamplerDesc.BorderColor[1] = LinearBorderColor.G;
SamplerDesc.BorderColor[2] = LinearBorderColor.B;
SamplerDesc.BorderColor[3] = LinearBorderColor.A;
SamplerDesc.ComparisonFunc = TranslateSamplerCompareFunction(Initializer.SamplerComparisonFunction);
// D3D11 will return the same pointer if the particular state description was already created
TRefCountPtr<ID3D11SamplerState> SamplerStateHandle;
VERIFYD3D11RESULT_EX(Direct3DDevice->CreateSamplerState(&SamplerDesc, SamplerStateHandle.GetInitReference()), Direct3DDevice);
FScopeLock Lock(&GSamplerStateCacheCS);
FD3D11SamplerState** Found = GSamplerStateCache.Find(SamplerStateHandle);
if (Found)
{
return *Found;
}
FD3D11SamplerState* SamplerState = new FD3D11SamplerState;
SamplerState->Resource = SamplerStateHandle;
// Manually add reference as we control the creation/destructions
SamplerState->AddRef();
GSamplerStateCache.Add(SamplerStateHandle.GetReference(), SamplerState);
return SamplerState;
}
FRasterizerStateRHIRef FD3D11DynamicRHI::RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer)
{
D3D11_RASTERIZER_DESC RasterizerDesc;
FMemory::Memzero(&RasterizerDesc,sizeof(D3D11_RASTERIZER_DESC));
RasterizerDesc.CullMode = TranslateCullMode(Initializer.CullMode);
RasterizerDesc.FillMode = TranslateFillMode(Initializer.FillMode);
RasterizerDesc.SlopeScaledDepthBias = Initializer.SlopeScaleDepthBias;
RasterizerDesc.FrontCounterClockwise = true;
RasterizerDesc.DepthBias = FMath::FloorToInt(Initializer.DepthBias * (float)(1 << 24));
RasterizerDesc.DepthClipEnable = Initializer.DepthClipMode == ERasterizerDepthClipMode::DepthClip;
RasterizerDesc.MultisampleEnable = Initializer.bAllowMSAA;
RasterizerDesc.ScissorEnable = true;
FD3D11RasterizerState* RasterizerState = new FD3D11RasterizerState;
VERIFYD3D11RESULT_EX(Direct3DDevice->CreateRasterizerState(&RasterizerDesc,RasterizerState->Resource.GetInitReference()), Direct3DDevice);
return RasterizerState;
}
FDepthStencilStateRHIRef FD3D11DynamicRHI::RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer)
{
FD3D11DepthStencilState* DepthStencilState = new FD3D11DepthStencilState;
D3D11_DEPTH_STENCIL_DESC DepthStencilDesc;
FMemory::Memzero(&DepthStencilDesc,sizeof(D3D11_DEPTH_STENCIL_DESC));
// depth part
DepthStencilDesc.DepthEnable = Initializer.DepthTest != CF_Always || Initializer.bEnableDepthWrite;
DepthStencilDesc.DepthWriteMask = Initializer.bEnableDepthWrite ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
DepthStencilDesc.DepthFunc = TranslateCompareFunction(Initializer.DepthTest);
// stencil part
DepthStencilDesc.StencilEnable = Initializer.bEnableFrontFaceStencil || Initializer.bEnableBackFaceStencil;
DepthStencilDesc.StencilReadMask = Initializer.StencilReadMask;
DepthStencilDesc.StencilWriteMask = Initializer.StencilWriteMask;
DepthStencilDesc.FrontFace.StencilFunc = TranslateCompareFunction(Initializer.FrontFaceStencilTest);
DepthStencilDesc.FrontFace.StencilFailOp = TranslateStencilOp(Initializer.FrontFaceStencilFailStencilOp);
DepthStencilDesc.FrontFace.StencilDepthFailOp = TranslateStencilOp(Initializer.FrontFaceDepthFailStencilOp);
DepthStencilDesc.FrontFace.StencilPassOp = TranslateStencilOp(Initializer.FrontFacePassStencilOp);
if( Initializer.bEnableBackFaceStencil )
{
DepthStencilDesc.BackFace.StencilFunc = TranslateCompareFunction(Initializer.BackFaceStencilTest);
DepthStencilDesc.BackFace.StencilFailOp = TranslateStencilOp(Initializer.BackFaceStencilFailStencilOp);
DepthStencilDesc.BackFace.StencilDepthFailOp = TranslateStencilOp(Initializer.BackFaceDepthFailStencilOp);
DepthStencilDesc.BackFace.StencilPassOp = TranslateStencilOp(Initializer.BackFacePassStencilOp);
}
else
{
DepthStencilDesc.BackFace = DepthStencilDesc.FrontFace;
}
const bool bStencilOpIsKeep =
Initializer.FrontFaceStencilFailStencilOp == SO_Keep
&& Initializer.FrontFaceDepthFailStencilOp == SO_Keep
&& Initializer.FrontFacePassStencilOp == SO_Keep
&& Initializer.BackFaceStencilFailStencilOp == SO_Keep
&& Initializer.BackFaceDepthFailStencilOp == SO_Keep
&& Initializer.BackFacePassStencilOp == SO_Keep;
const bool bMayWriteStencil = Initializer.StencilWriteMask != 0 && !bStencilOpIsKeep;
DepthStencilState->AccessType.SetDepthStencilWrite(Initializer.bEnableDepthWrite, bMayWriteStencil);
VERIFYD3D11RESULT_EX(Direct3DDevice->CreateDepthStencilState(&DepthStencilDesc,DepthStencilState->Resource.GetInitReference()), Direct3DDevice);
return DepthStencilState;
}
FBlendStateRHIRef FD3D11DynamicRHI::RHICreateBlendState(const FBlendStateInitializerRHI& Initializer)
{
D3D11_BLEND_DESC BlendDesc;
FMemory::Memzero(&BlendDesc,sizeof(D3D11_BLEND_DESC));
BlendDesc.AlphaToCoverageEnable = Initializer.bUseAlphaToCoverage;
BlendDesc.IndependentBlendEnable = Initializer.bUseIndependentRenderTargetBlendStates;
static_assert(MaxSimultaneousRenderTargets <= D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, "Too many MRTs.");
for(uint32 RenderTargetIndex = 0;RenderTargetIndex < MaxSimultaneousRenderTargets;++RenderTargetIndex)
{
const FBlendStateInitializerRHI::FRenderTarget& RenderTargetInitializer = Initializer.RenderTargets[RenderTargetIndex];
D3D11_RENDER_TARGET_BLEND_DESC& RenderTarget = BlendDesc.RenderTarget[RenderTargetIndex];
RenderTarget.BlendEnable =
RenderTargetInitializer.ColorBlendOp != BO_Add || RenderTargetInitializer.ColorDestBlend != BF_Zero || RenderTargetInitializer.ColorSrcBlend != BF_One ||
RenderTargetInitializer.AlphaBlendOp != BO_Add || RenderTargetInitializer.AlphaDestBlend != BF_Zero || RenderTargetInitializer.AlphaSrcBlend != BF_One;
RenderTarget.BlendOp = TranslateBlendOp(RenderTargetInitializer.ColorBlendOp);
RenderTarget.SrcBlend = TranslateBlendFactor(RenderTargetInitializer.ColorSrcBlend);
RenderTarget.DestBlend = TranslateBlendFactor(RenderTargetInitializer.ColorDestBlend);
RenderTarget.BlendOpAlpha = TranslateBlendOp(RenderTargetInitializer.AlphaBlendOp);
RenderTarget.SrcBlendAlpha = TranslateBlendFactor(RenderTargetInitializer.AlphaSrcBlend);
RenderTarget.DestBlendAlpha = TranslateBlendFactor(RenderTargetInitializer.AlphaDestBlend);
RenderTarget.RenderTargetWriteMask =
((RenderTargetInitializer.ColorWriteMask & CW_RED) ? D3D11_COLOR_WRITE_ENABLE_RED : 0)
| ((RenderTargetInitializer.ColorWriteMask & CW_GREEN) ? D3D11_COLOR_WRITE_ENABLE_GREEN : 0)
| ((RenderTargetInitializer.ColorWriteMask & CW_BLUE) ? D3D11_COLOR_WRITE_ENABLE_BLUE : 0)
| ((RenderTargetInitializer.ColorWriteMask & CW_ALPHA) ? D3D11_COLOR_WRITE_ENABLE_ALPHA : 0);
}
FD3D11BlendState* BlendState = new FD3D11BlendState;
VERIFYD3D11RESULT_EX(Direct3DDevice->CreateBlendState(&BlendDesc,BlendState->Resource.GetInitReference()), Direct3DDevice);
return BlendState;
}