375 lines
14 KiB
C++
375 lines
14 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
VulkanState.cpp: Vulkan state implementation.
|
|
=============================================================================*/
|
|
|
|
#include "VulkanState.h"
|
|
#include "VulkanPendingState.h"
|
|
#include "VulkanDescriptorSets.h"
|
|
#include "RHIUtilities.h"
|
|
|
|
static FCriticalSection GSamplerHashLock;
|
|
|
|
inline VkSamplerMipmapMode TranslateMipFilterMode(ESamplerFilter InFilter)
|
|
{
|
|
switch (InFilter)
|
|
{
|
|
case SF_Point: return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
case SF_Bilinear: return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
case SF_Trilinear: return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
case SF_AnisotropicPoint: return VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
case SF_AnisotropicLinear: return VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
checkf(0, TEXT("Unknown Mip ESamplerFilter %d"), (uint32)InFilter);
|
|
return VK_SAMPLER_MIPMAP_MODE_MAX_ENUM;
|
|
}
|
|
|
|
inline VkFilter TranslateMinMagFilterMode(ESamplerFilter InFilter)
|
|
{
|
|
switch (InFilter)
|
|
{
|
|
case SF_Point: return VK_FILTER_NEAREST;
|
|
case SF_Bilinear: return VK_FILTER_LINEAR;
|
|
case SF_Trilinear: return VK_FILTER_LINEAR;
|
|
case SF_AnisotropicPoint:
|
|
case SF_AnisotropicLinear: return VK_FILTER_LINEAR;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
checkf(0, TEXT("Unknown ESamplerFilter %d"), (uint32)InFilter);
|
|
return VK_FILTER_MAX_ENUM;
|
|
}
|
|
|
|
inline VkSamplerAddressMode TranslateWrapMode(ESamplerAddressMode InAddressMode)
|
|
{
|
|
switch (InAddressMode)
|
|
{
|
|
case AM_Wrap: return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
case AM_Clamp: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
case AM_Mirror: return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
|
case AM_Border: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
checkf(0, TEXT("Unknown Wrap ESamplerAddressMode %d"), (uint32)InAddressMode);
|
|
return VK_SAMPLER_ADDRESS_MODE_MAX_ENUM;
|
|
}
|
|
|
|
inline VkCompareOp TranslateSamplerCompareFunction(ESamplerCompareFunction InSamplerComparisonFunction)
|
|
{
|
|
switch (InSamplerComparisonFunction)
|
|
{
|
|
case SCF_Less: return VK_COMPARE_OP_LESS;
|
|
case SCF_Never: return VK_COMPARE_OP_NEVER;
|
|
default:
|
|
break;
|
|
};
|
|
|
|
checkf(0, TEXT("Unknown ESamplerCompareFunction %d"), (uint32)InSamplerComparisonFunction);
|
|
return VK_COMPARE_OP_MAX_ENUM;
|
|
}
|
|
|
|
static inline VkBlendOp BlendOpToVulkan(EBlendOperation InOp)
|
|
{
|
|
switch (InOp)
|
|
{
|
|
case BO_Add: return VK_BLEND_OP_ADD;
|
|
case BO_Subtract: return VK_BLEND_OP_SUBTRACT;
|
|
case BO_Min: return VK_BLEND_OP_MIN;
|
|
case BO_Max: return VK_BLEND_OP_MAX;
|
|
case BO_ReverseSubtract: return VK_BLEND_OP_REVERSE_SUBTRACT;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
checkf(0, TEXT("Unknown EBlendOperation %d"), (uint32)InOp);
|
|
return VK_BLEND_OP_MAX_ENUM;
|
|
}
|
|
|
|
static inline VkBlendFactor BlendFactorToVulkan(EBlendFactor InFactor)
|
|
{
|
|
switch (InFactor)
|
|
{
|
|
case BF_Zero: return VK_BLEND_FACTOR_ZERO;
|
|
case BF_One: return VK_BLEND_FACTOR_ONE;
|
|
case BF_SourceColor: return VK_BLEND_FACTOR_SRC_COLOR;
|
|
case BF_InverseSourceColor: return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
|
|
case BF_SourceAlpha: return VK_BLEND_FACTOR_SRC_ALPHA;
|
|
case BF_InverseSourceAlpha: return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
case BF_DestAlpha: return VK_BLEND_FACTOR_DST_ALPHA;
|
|
case BF_InverseDestAlpha: return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
|
|
case BF_DestColor: return VK_BLEND_FACTOR_DST_COLOR;
|
|
case BF_InverseDestColor: return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
|
|
case BF_ConstantBlendFactor: return VK_BLEND_FACTOR_CONSTANT_COLOR;
|
|
case BF_InverseConstantBlendFactor: return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
|
|
case BF_Source1Color: return VK_BLEND_FACTOR_SRC1_COLOR;
|
|
case BF_InverseSource1Color: return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
|
|
case BF_Source1Alpha: return VK_BLEND_FACTOR_SRC1_ALPHA;
|
|
case BF_InverseSource1Alpha: return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
checkf(0, TEXT("Unknown EBlendFactor %d"), (uint32)InFactor);
|
|
return VK_BLEND_FACTOR_MAX_ENUM;
|
|
}
|
|
|
|
static inline VkCompareOp CompareOpToVulkan(ECompareFunction InOp)
|
|
{
|
|
switch (InOp)
|
|
{
|
|
case CF_Less: return VK_COMPARE_OP_LESS;
|
|
case CF_LessEqual: return VK_COMPARE_OP_LESS_OR_EQUAL;
|
|
case CF_Greater: return VK_COMPARE_OP_GREATER;
|
|
case CF_GreaterEqual: return VK_COMPARE_OP_GREATER_OR_EQUAL;
|
|
case CF_Equal: return VK_COMPARE_OP_EQUAL;
|
|
case CF_NotEqual: return VK_COMPARE_OP_NOT_EQUAL;
|
|
case CF_Never: return VK_COMPARE_OP_NEVER;
|
|
case CF_Always: return VK_COMPARE_OP_ALWAYS;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
checkf(0, TEXT("Unknown ECompareFunction %d"), (uint32)InOp);
|
|
return VK_COMPARE_OP_MAX_ENUM;
|
|
}
|
|
|
|
static inline VkStencilOp StencilOpToVulkan(EStencilOp InOp)
|
|
{
|
|
VkStencilOp OutOp = VK_STENCIL_OP_MAX_ENUM;
|
|
|
|
switch (InOp)
|
|
{
|
|
case SO_Keep: return VK_STENCIL_OP_KEEP;
|
|
case SO_Zero: return VK_STENCIL_OP_ZERO;
|
|
case SO_Replace: return VK_STENCIL_OP_REPLACE;
|
|
case SO_SaturatedIncrement: return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
|
|
case SO_SaturatedDecrement: return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
|
|
case SO_Invert: return VK_STENCIL_OP_INVERT;
|
|
case SO_Increment: return VK_STENCIL_OP_INCREMENT_AND_WRAP;
|
|
case SO_Decrement: return VK_STENCIL_OP_DECREMENT_AND_WRAP;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
checkf(0, TEXT("Unknown EStencilOp %d"), (uint32)InOp);
|
|
return VK_STENCIL_OP_MAX_ENUM;
|
|
}
|
|
|
|
static inline VkPolygonMode RasterizerFillModeToVulkan(ERasterizerFillMode InFillMode)
|
|
{
|
|
switch (InFillMode)
|
|
{
|
|
case FM_Point: return VK_POLYGON_MODE_POINT;
|
|
case FM_Wireframe: return VK_POLYGON_MODE_LINE;
|
|
case FM_Solid: return VK_POLYGON_MODE_FILL;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
checkf(0, TEXT("Unknown ERasterizerFillMode %d"), (uint32)InFillMode);
|
|
return VK_POLYGON_MODE_MAX_ENUM;
|
|
}
|
|
|
|
static inline VkCullModeFlags RasterizerCullModeToVulkan(ERasterizerCullMode InCullMode)
|
|
{
|
|
switch (InCullMode)
|
|
{
|
|
case CM_None: return VK_CULL_MODE_NONE;
|
|
case CM_CW: return VK_CULL_MODE_FRONT_BIT;
|
|
case CM_CCW: return VK_CULL_MODE_BACK_BIT;
|
|
default: break;
|
|
}
|
|
|
|
checkf(0, TEXT("Unknown ERasterizerCullMode %d"), (uint32)InCullMode);
|
|
return VK_CULL_MODE_NONE;
|
|
}
|
|
|
|
|
|
void FVulkanSamplerState::SetupSamplerCreateInfo(const FSamplerStateInitializerRHI& Initializer, FVulkanDevice& InDevice, VkSamplerCreateInfo& OutSamplerInfo)
|
|
{
|
|
ZeroVulkanStruct(OutSamplerInfo, VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
|
|
|
|
OutSamplerInfo.magFilter = TranslateMinMagFilterMode(Initializer.Filter);
|
|
OutSamplerInfo.minFilter = TranslateMinMagFilterMode(Initializer.Filter);
|
|
OutSamplerInfo.mipmapMode = TranslateMipFilterMode(Initializer.Filter);
|
|
OutSamplerInfo.addressModeU = TranslateWrapMode(Initializer.AddressU);
|
|
OutSamplerInfo.addressModeV = TranslateWrapMode(Initializer.AddressV);
|
|
OutSamplerInfo.addressModeW = TranslateWrapMode(Initializer.AddressW);
|
|
|
|
OutSamplerInfo.mipLodBias = Initializer.MipBias;
|
|
|
|
OutSamplerInfo.maxAnisotropy = 1.0f;
|
|
if (Initializer.Filter == SF_AnisotropicLinear || Initializer.Filter == SF_AnisotropicPoint)
|
|
{
|
|
OutSamplerInfo.maxAnisotropy = FMath::Clamp((float)ComputeAnisotropyRT(Initializer.MaxAnisotropy), 1.0f, InDevice.GetLimits().maxSamplerAnisotropy);
|
|
}
|
|
OutSamplerInfo.anisotropyEnable = OutSamplerInfo.maxAnisotropy > 1.0f;
|
|
|
|
OutSamplerInfo.compareEnable = Initializer.SamplerComparisonFunction != SCF_Never ? VK_TRUE : VK_FALSE;
|
|
OutSamplerInfo.compareOp = TranslateSamplerCompareFunction(Initializer.SamplerComparisonFunction);
|
|
OutSamplerInfo.minLod = Initializer.MinMipLevel;
|
|
OutSamplerInfo.maxLod = Initializer.MaxMipLevel;
|
|
OutSamplerInfo.borderColor = Initializer.BorderColor == 0 ? VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK : VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
|
}
|
|
|
|
|
|
FVulkanSamplerState::FVulkanSamplerState(const VkSamplerCreateInfo& InInfo, FVulkanDevice& InDevice, const bool bInIsImmutable)
|
|
: Sampler(VK_NULL_HANDLE)
|
|
, SamplerId(0)
|
|
, BindlessHandle()
|
|
, bIsImmutable(bInIsImmutable)
|
|
{
|
|
VERIFYVULKANRESULT(VulkanRHI::vkCreateSampler(InDevice.GetInstanceHandle(), &InInfo, VULKAN_CPU_ALLOCATOR, &Sampler));
|
|
|
|
if (UseVulkanDescriptorCache())
|
|
{
|
|
SamplerId = ++GVulkanSamplerHandleIdCounter;
|
|
}
|
|
|
|
if (InDevice.SupportsBindless() && (RHIGetRuntimeBindlessConfiguration(GMaxRHIShaderPlatform) != ERHIBindlessConfiguration::Disabled))
|
|
{
|
|
FVulkanBindlessDescriptorManager* BindlessDescriptorManager = InDevice.GetBindlessDescriptorManager();
|
|
BindlessHandle = BindlessDescriptorManager->ReserveDescriptor(VK_DESCRIPTOR_TYPE_SAMPLER);
|
|
BindlessDescriptorManager->UpdateSampler(BindlessHandle, Sampler);
|
|
}
|
|
}
|
|
|
|
FVulkanRasterizerState::FVulkanRasterizerState(const FRasterizerStateInitializerRHI& InInitializer)
|
|
: Initializer(InInitializer)
|
|
{
|
|
FVulkanRasterizerState::ResetCreateInfo(RasterizerState);
|
|
|
|
// @todo vulkan: I'm assuming that Solid and Wireframe wouldn't ever be mixed within the same BoundShaderState, so we are ignoring the fill mode as a unique identifier
|
|
//checkf(Initializer.FillMode == FM_Solid, TEXT("PIPELINE KEY: Only FM_Solid is supported fill mode [got %d]"), (int32)Initializer.FillMode);
|
|
|
|
RasterizerState.polygonMode = RasterizerFillModeToVulkan(Initializer.FillMode);
|
|
RasterizerState.cullMode = RasterizerCullModeToVulkan(Initializer.CullMode);
|
|
|
|
RasterizerState.depthClampEnable = InInitializer.DepthClipMode == ERasterizerDepthClipMode::DepthClamp ? VK_TRUE : VK_FALSE;
|
|
RasterizerState.depthBiasEnable = Initializer.DepthBias != 0.0f ? VK_TRUE : VK_FALSE;
|
|
//RasterizerState.rasterizerDiscardEnable = VK_FALSE;
|
|
|
|
RasterizerState.depthBiasSlopeFactor = Initializer.SlopeScaleDepthBias;
|
|
RasterizerState.depthBiasConstantFactor = Initializer.DepthBias;
|
|
|
|
//RasterizerState.lineWidth = 1.0f;
|
|
}
|
|
|
|
void FVulkanDepthStencilState::SetupCreateInfo(const FGraphicsPipelineStateInitializer& GfxPSOInit, VkPipelineDepthStencilStateCreateInfo& OutDepthStencilState)
|
|
{
|
|
ZeroVulkanStruct(OutDepthStencilState, VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO);
|
|
|
|
OutDepthStencilState.depthTestEnable = (Initializer.DepthTest != CF_Always || Initializer.bEnableDepthWrite) ? VK_TRUE : VK_FALSE;
|
|
OutDepthStencilState.depthCompareOp = CompareOpToVulkan(Initializer.DepthTest);
|
|
OutDepthStencilState.depthWriteEnable = Initializer.bEnableDepthWrite ? VK_TRUE : VK_FALSE;
|
|
|
|
{
|
|
// This will be filled in from the PSO
|
|
OutDepthStencilState.depthBoundsTestEnable = GfxPSOInit.bDepthBounds;
|
|
OutDepthStencilState.minDepthBounds = 0.0f;
|
|
OutDepthStencilState.maxDepthBounds = 1.0f;
|
|
}
|
|
|
|
OutDepthStencilState.stencilTestEnable = (Initializer.bEnableFrontFaceStencil || Initializer.bEnableBackFaceStencil) ? VK_TRUE : VK_FALSE;
|
|
|
|
// Front
|
|
OutDepthStencilState.back.failOp = StencilOpToVulkan(Initializer.FrontFaceStencilFailStencilOp);
|
|
OutDepthStencilState.back.passOp = StencilOpToVulkan(Initializer.FrontFacePassStencilOp);
|
|
OutDepthStencilState.back.depthFailOp = StencilOpToVulkan(Initializer.FrontFaceDepthFailStencilOp);
|
|
OutDepthStencilState.back.compareOp = CompareOpToVulkan(Initializer.FrontFaceStencilTest);
|
|
OutDepthStencilState.back.compareMask = Initializer.StencilReadMask;
|
|
OutDepthStencilState.back.writeMask = Initializer.StencilWriteMask;
|
|
OutDepthStencilState.back.reference = 0;
|
|
|
|
if (Initializer.bEnableBackFaceStencil)
|
|
{
|
|
// Back
|
|
OutDepthStencilState.front.failOp = StencilOpToVulkan(Initializer.BackFaceStencilFailStencilOp);
|
|
OutDepthStencilState.front.passOp = StencilOpToVulkan(Initializer.BackFacePassStencilOp);
|
|
OutDepthStencilState.front.depthFailOp = StencilOpToVulkan(Initializer.BackFaceDepthFailStencilOp);
|
|
OutDepthStencilState.front.compareOp = CompareOpToVulkan(Initializer.BackFaceStencilTest);
|
|
OutDepthStencilState.front.compareMask = Initializer.StencilReadMask;
|
|
OutDepthStencilState.front.writeMask = Initializer.StencilWriteMask;
|
|
OutDepthStencilState.front.reference = 0;
|
|
}
|
|
else
|
|
{
|
|
OutDepthStencilState.front = OutDepthStencilState.back;
|
|
}
|
|
}
|
|
|
|
FVulkanBlendState::FVulkanBlendState(const FBlendStateInitializerRHI& InInitializer)
|
|
{
|
|
Initializer = InInitializer;
|
|
for (uint32 Index = 0; Index < MaxSimultaneousRenderTargets; ++Index)
|
|
{
|
|
const FBlendStateInitializerRHI::FRenderTarget& ColorTarget = Initializer.RenderTargets[Index];
|
|
VkPipelineColorBlendAttachmentState& BlendState = BlendStates[Index];
|
|
FMemory::Memzero(BlendState);
|
|
|
|
BlendState.colorBlendOp = BlendOpToVulkan(ColorTarget.ColorBlendOp);
|
|
BlendState.alphaBlendOp = BlendOpToVulkan(ColorTarget.AlphaBlendOp);
|
|
|
|
BlendState.dstColorBlendFactor = BlendFactorToVulkan(ColorTarget.ColorDestBlend);
|
|
BlendState.dstAlphaBlendFactor = BlendFactorToVulkan(ColorTarget.AlphaDestBlend);
|
|
|
|
BlendState.srcColorBlendFactor = BlendFactorToVulkan(ColorTarget.ColorSrcBlend);
|
|
BlendState.srcAlphaBlendFactor = BlendFactorToVulkan(ColorTarget.AlphaSrcBlend);
|
|
|
|
BlendState.blendEnable =
|
|
(ColorTarget.ColorBlendOp != BO_Add || ColorTarget.ColorDestBlend != BF_Zero || ColorTarget.ColorSrcBlend != BF_One ||
|
|
ColorTarget.AlphaBlendOp != BO_Add || ColorTarget.AlphaDestBlend != BF_Zero || ColorTarget.AlphaSrcBlend != BF_One) ? VK_TRUE : VK_FALSE;
|
|
|
|
BlendState.colorWriteMask = (ColorTarget.ColorWriteMask & CW_RED) ? VK_COLOR_COMPONENT_R_BIT : 0;
|
|
BlendState.colorWriteMask |= (ColorTarget.ColorWriteMask & CW_GREEN) ? VK_COLOR_COMPONENT_G_BIT : 0;
|
|
BlendState.colorWriteMask |= (ColorTarget.ColorWriteMask & CW_BLUE) ? VK_COLOR_COMPONENT_B_BIT : 0;
|
|
BlendState.colorWriteMask |= (ColorTarget.ColorWriteMask & CW_ALPHA) ? VK_COLOR_COMPONENT_A_BIT : 0;
|
|
}
|
|
}
|
|
|
|
FSamplerStateRHIRef FVulkanDynamicRHI::RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer)
|
|
{
|
|
VkSamplerCreateInfo SamplerInfo;
|
|
FVulkanSamplerState::SetupSamplerCreateInfo(Initializer, *Device, SamplerInfo);
|
|
|
|
uint32 CRC = FCrc::MemCrc32(&SamplerInfo, sizeof(SamplerInfo));
|
|
|
|
{
|
|
FScopeLock ScopeLock(&GSamplerHashLock);
|
|
TMap<uint32, FSamplerStateRHIRef>& SamplerMap = Device->GetSamplerMap();
|
|
FSamplerStateRHIRef* Found = SamplerMap.Find(CRC);
|
|
if (Found)
|
|
{
|
|
return *Found;
|
|
}
|
|
|
|
FSamplerStateRHIRef New = new FVulkanSamplerState(SamplerInfo, *Device);
|
|
SamplerMap.Add(CRC, New);
|
|
return New;
|
|
}
|
|
}
|
|
|
|
FRasterizerStateRHIRef FVulkanDynamicRHI::RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer)
|
|
{
|
|
return new FVulkanRasterizerState(Initializer);
|
|
}
|
|
|
|
|
|
FDepthStencilStateRHIRef FVulkanDynamicRHI::RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer)
|
|
{
|
|
return new FVulkanDepthStencilState(Initializer);
|
|
}
|
|
|
|
|
|
FBlendStateRHIRef FVulkanDynamicRHI::RHICreateBlendState(const FBlendStateInitializerRHI& Initializer)
|
|
{
|
|
return new FVulkanBlendState(Initializer);
|
|
}
|