// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= RHI.h: Render Hardware Interface definitions. =============================================================================*/ #pragma once #include "Containers/ContainersFwd.h" #include "RHIDefinitions.h" #include "Templates/TypeHash.h" // This must be before StaticArray to resolve adl compile error in nopch unity builds #include "Containers/StaticArray.h" #include "Containers/StringFwd.h" #include "Math/IntRect.h" #include "Math/PerspectiveMatrix.h" #include "Math/ScaleMatrix.h" #include "Math/TranslationMatrix.h" #include "PixelFormat.h" #include "GpuProfilerTrace.h" #include "RHIShaderPlatform.h" #include "RHIFeatureLevel.h" #include "RHIAccess.h" #include "RHIGlobals.h" class FResourceArrayInterface; class FResourceBulkDataInterface; class FRHICommandList; /** * RHI configuration settings. */ #if (RHI_NEW_GPU_PROFILER == 0) namespace RHIConfig { RHI_API bool ShouldSaveScreenshotAfterProfilingGPU(); RHI_API bool ShouldShowProfilerAfterProfilingGPU(); RHI_API float GetGPUHitchThreshold(); } #endif /** * RHI capabilities. */ // to trigger GPU specific optimizations and fallbacks RHI_API bool IsRHIDeviceAMD(); // to trigger GPU specific optimizations and fallbacks RHI_API bool IsRHIDeviceIntel(); // to trigger GPU specific optimizations and fallbacks RHI_API bool IsRHIDeviceNVIDIA(); // to trigger GPU specific optimizations and fallbacks RHI_API bool IsRHIDeviceApple(); namespace UE::RHI { // Returns true when GPU crash debugging is enabled. RHI_API bool UseGPUCrashDebugging(); // True when using engine-managed GPU breadcrumb tracking RHI_API bool UseGPUCrashBreadcrumbs(); // Used to determine whether specific GPU crash debugging features are enabled given the combination of command line switches and console variable settings RHI_API bool ShouldEnableGPUCrashFeature(IConsoleVariable& CVar, TCHAR const* CommandLineSwitch); } // helper to return the shader language version for Metal shader. RHI_API uint32 RHIGetMetalShaderLanguageVersion(const FStaticShaderPlatform Platform); // helper to check if a preview feature level has been requested. RHI_API bool RHIGetPreviewFeatureLevel(ERHIFeatureLevel::Type& PreviewFeatureLevelOUT); // helper to check if preferred EPixelFormat is supported, return one if it is not RHI_API EPixelFormat RHIPreferredPixelFormatHint(EPixelFormat PreferredPixelFormat); // helper to check which resource type should be used for clear (UAV) replacement shaders. RHI_API int32 RHIGetPreferredClearUAVRectPSResourceType(const FStaticShaderPlatform Platform); // helper to force dump all RHI resource to CSV file RHI_API void RHIDumpResourceMemoryToCSV(); // helper to check whether rendering to volume textures is supported. This takes both GSupportsVolumeTextureRendering and DDPI entries into account as this is dependent on the preview platform. RHI_API bool RHISupportsVolumeTextureRendering(const FStaticShaderPlatform Platform); struct FRHIResourceStats { FName Name; FName OwnerName; FString Type; FString Flags; uint64 SizeInBytes = 0; bool bResident = false; bool bMarkedForDelete = false; bool bTransient = false; bool bStreaming = false; bool bRenderTarget = false; bool bDepthStencil = false; bool bUnorderedAccessView = false; bool bRayTracingAccelerationStructure = false; bool bHasFlags = false; FRHIResourceStats(const FName& InName, const FName& InOwnerName, const FString& InType, const FString& InFlags, const uint64& InSizeInBytes, bool bInResident, bool bInMarkedForDelete, bool bInTransient, bool bInStreaming, bool bInRT, bool bInDS, bool bInUAV, bool bInRTAS, bool bInHasFlags) : Name(InName) , OwnerName(InOwnerName) , Type(InType) , Flags(InFlags) , SizeInBytes(InSizeInBytes) , bResident(bInResident) , bMarkedForDelete(bInMarkedForDelete) , bTransient(bInTransient) , bStreaming(bInStreaming) , bRenderTarget(bInRT) , bDepthStencil(bInDS) , bUnorderedAccessView(bInUAV) , bRayTracingAccelerationStructure(bInRTAS) , bHasFlags(bInHasFlags) { } }; RHI_API void RHIGetTrackedResourceStats(TArray>& OutResourceStats); #include "MultiGPU.h" // Calculate the index of the sample in GRHIDefaultMSAASampleOffsets extern RHI_API int32 CalculateMSAASampleArrayIndex(int32 NumSamples, int32 SampleIndex); // Gets the MSAA sample's offset from the center of the pixel coordinate. inline FVector2f GetMSAASampleOffsets(int32 NumSamples, int32 SampleIndex) { return GRHIDefaultMSAASampleOffsets[CalculateMSAASampleArrayIndex(NumSamples, SampleIndex)]; } /** Initialize the 'best guess' pixel format capabilities. Platform formats and support must be filled out before calling this. */ extern RHI_API void RHIInitDefaultPixelFormatCapabilities(); inline bool RHIPixelFormatHasCapabilities(EPixelFormat InFormat, EPixelFormatCapabilities InCapabilities) { return UE::PixelFormat::HasCapabilities(InFormat, InCapabilities); } inline bool RHIIsTypedUAVLoadSupported(EPixelFormat InFormat) { return UE::PixelFormat::HasCapabilities(InFormat, EPixelFormatCapabilities::TypedUAVLoad); } inline bool RHIIsTypedUAVStoreSupported(EPixelFormat InFormat) { return UE::PixelFormat::HasCapabilities(InFormat, EPixelFormatCapabilities::TypedUAVStore); } /** * Returns the memory required to store an image in the given pixel format (EPixelFormat). Use * GPixelFormats[Format].Get2D/3DImageSizeInBytes instead, unless you need PF_A1. */ extern RHI_API SIZE_T CalculateImageBytes(uint32 SizeX,uint32 SizeY,uint32 SizeZ,uint8 Format); /** * Adjusts a projection matrix to output in the correct clip space for the * current RHI. Unreal projection matrices follow certain conventions and * need to be patched for some RHIs. All projection matrices should be adjusted * before being used for rendering! */ inline FMatrix AdjustProjectionMatrixForRHI(const FMatrix& InProjectionMatrix) { FScaleMatrix ClipSpaceFixScale(FVector(1.0f, GProjectionSignY, 1.0f - GMinClipZ)); FTranslationMatrix ClipSpaceFixTranslate(FVector(0.0f, 0.0f, GMinClipZ)); return InProjectionMatrix * ClipSpaceFixScale * ClipSpaceFixTranslate; } /** Set runtime selection of mobile feature level preview. */ RHI_API void RHISetMobilePreviewFeatureLevel(ERHIFeatureLevel::Type MobilePreviewFeatureLevel); struct FVertexElement { uint8 StreamIndex; uint8 Offset; TEnumAsByte Type; uint8 AttributeIndex; uint16 Stride; /** * Whether to use instance index or vertex index to consume the element. * eg if bUseInstanceIndex is 0, the element will be repeated for every instance. */ uint16 bUseInstanceIndex; FVertexElement() {} FVertexElement(uint8 InStreamIndex,uint8 InOffset,EVertexElementType InType,uint8 InAttributeIndex,uint16 InStride,bool bInUseInstanceIndex = false): StreamIndex(InStreamIndex), Offset(InOffset), Type(InType), AttributeIndex(InAttributeIndex), Stride(InStride), bUseInstanceIndex(bInUseInstanceIndex) {} bool operator==(const FVertexElement& Other) const { return (StreamIndex == Other.StreamIndex && Offset == Other.Offset && Type == Other.Type && AttributeIndex == Other.AttributeIndex && Stride == Other.Stride && bUseInstanceIndex == Other.bUseInstanceIndex); } friend FArchive& operator<<(FArchive& Ar,FVertexElement& Element) { Ar << Element.StreamIndex; Ar << Element.Offset; Ar << Element.Type; Ar << Element.AttributeIndex; Ar << Element.Stride; Ar << Element.bUseInstanceIndex; return Ar; } RHI_API FString ToString() const; RHI_API void FromString(const FString& Src); RHI_API void FromString(const FStringView& Src); }; typedef TArray > FVertexDeclarationElementList; struct FSamplerStateInitializerRHI { FSamplerStateInitializerRHI() {} FSamplerStateInitializerRHI( ESamplerFilter InFilter, ESamplerAddressMode InAddressU = AM_Wrap, ESamplerAddressMode InAddressV = AM_Wrap, ESamplerAddressMode InAddressW = AM_Wrap, float InMipBias = 0, int32 InMaxAnisotropy = 0, float InMinMipLevel = 0, float InMaxMipLevel = FLT_MAX, uint32 InBorderColor = 0, /** Only supported in D3D11 */ ESamplerCompareFunction InSamplerComparisonFunction = SCF_Never ) : Filter(InFilter) , AddressU(InAddressU) , AddressV(InAddressV) , AddressW(InAddressW) , MipBias(InMipBias) , MinMipLevel(InMinMipLevel) , MaxMipLevel(InMaxMipLevel) , MaxAnisotropy(InMaxAnisotropy) , BorderColor(InBorderColor) , SamplerComparisonFunction(InSamplerComparisonFunction) { } TEnumAsByte Filter = SF_Point; TEnumAsByte AddressU = AM_Wrap; TEnumAsByte AddressV = AM_Wrap; TEnumAsByte AddressW = AM_Wrap; float MipBias = 0.0f; /** Smallest mip map level that will be used, where 0 is the highest resolution mip level. */ float MinMipLevel = 0.0f; /** Largest mip map level that will be used, where 0 is the highest resolution mip level. */ float MaxMipLevel = FLT_MAX; int32 MaxAnisotropy = 0; uint32 BorderColor = 0; TEnumAsByte SamplerComparisonFunction = SCF_Never; RHI_API friend uint32 GetTypeHash(const FSamplerStateInitializerRHI& Initializer); RHI_API friend bool operator== (const FSamplerStateInitializerRHI& A, const FSamplerStateInitializerRHI& B); }; struct FRasterizerStateInitializerRHI { TEnumAsByte FillMode = FM_Point; TEnumAsByte CullMode = CM_None; float DepthBias = 0.0f; float SlopeScaleDepthBias = 0.0f; ERasterizerDepthClipMode DepthClipMode = ERasterizerDepthClipMode::DepthClip; bool bAllowMSAA = false; PRAGMA_DISABLE_DEPRECATION_WARNINGS FRasterizerStateInitializerRHI() = default; FRasterizerStateInitializerRHI(const FRasterizerStateInitializerRHI&) = default; FRasterizerStateInitializerRHI(FRasterizerStateInitializerRHI&&) = default; FRasterizerStateInitializerRHI& operator=(const FRasterizerStateInitializerRHI&) = default; PRAGMA_ENABLE_DEPRECATION_WARNINGS FRasterizerStateInitializerRHI(ERasterizerFillMode InFillMode, ERasterizerCullMode InCullMode, bool bInAllowMSAA) : FillMode(InFillMode) , CullMode(InCullMode) , bAllowMSAA(bInAllowMSAA) { } FRasterizerStateInitializerRHI(ERasterizerFillMode InFillMode, ERasterizerCullMode InCullMode, float InDepthBias, float InSlopeScaleDepthBias, ERasterizerDepthClipMode InDepthClipMode, bool bInAllowMSAA) : FillMode(InFillMode) , CullMode(InCullMode) , DepthBias(InDepthBias) , SlopeScaleDepthBias(InSlopeScaleDepthBias) , DepthClipMode(InDepthClipMode) , bAllowMSAA(bInAllowMSAA) { } friend FArchive& operator<<(FArchive& Ar, FRasterizerStateInitializerRHI& RasterizerStateInitializer) { Ar << RasterizerStateInitializer.FillMode; Ar << RasterizerStateInitializer.CullMode; Ar << RasterizerStateInitializer.DepthBias; Ar << RasterizerStateInitializer.SlopeScaleDepthBias; Ar << RasterizerStateInitializer.DepthClipMode; Ar << RasterizerStateInitializer.bAllowMSAA; return Ar; } RHI_API friend uint32 GetTypeHash(const FRasterizerStateInitializerRHI& Initializer); RHI_API friend bool operator== (const FRasterizerStateInitializerRHI& A, const FRasterizerStateInitializerRHI& B); }; struct FDepthStencilStateInitializerRHI { bool bEnableDepthWrite; TEnumAsByte DepthTest; bool bEnableFrontFaceStencil; TEnumAsByte FrontFaceStencilTest; TEnumAsByte FrontFaceStencilFailStencilOp; TEnumAsByte FrontFaceDepthFailStencilOp; TEnumAsByte FrontFacePassStencilOp; bool bEnableBackFaceStencil; TEnumAsByte BackFaceStencilTest; TEnumAsByte BackFaceStencilFailStencilOp; TEnumAsByte BackFaceDepthFailStencilOp; TEnumAsByte BackFacePassStencilOp; uint8 StencilReadMask; uint8 StencilWriteMask; FDepthStencilStateInitializerRHI( bool bInEnableDepthWrite = true, ECompareFunction InDepthTest = CF_LessEqual, bool bInEnableFrontFaceStencil = false, ECompareFunction InFrontFaceStencilTest = CF_Always, EStencilOp InFrontFaceStencilFailStencilOp = SO_Keep, EStencilOp InFrontFaceDepthFailStencilOp = SO_Keep, EStencilOp InFrontFacePassStencilOp = SO_Keep, bool bInEnableBackFaceStencil = false, ECompareFunction InBackFaceStencilTest = CF_Always, EStencilOp InBackFaceStencilFailStencilOp = SO_Keep, EStencilOp InBackFaceDepthFailStencilOp = SO_Keep, EStencilOp InBackFacePassStencilOp = SO_Keep, uint8 InStencilReadMask = 0xFF, uint8 InStencilWriteMask = 0xFF ) : bEnableDepthWrite(bInEnableDepthWrite) , DepthTest(InDepthTest) , bEnableFrontFaceStencil(bInEnableFrontFaceStencil) , FrontFaceStencilTest(InFrontFaceStencilTest) , FrontFaceStencilFailStencilOp(InFrontFaceStencilFailStencilOp) , FrontFaceDepthFailStencilOp(InFrontFaceDepthFailStencilOp) , FrontFacePassStencilOp(InFrontFacePassStencilOp) , bEnableBackFaceStencil(bInEnableBackFaceStencil) , BackFaceStencilTest(InBackFaceStencilTest) , BackFaceStencilFailStencilOp(InBackFaceStencilFailStencilOp) , BackFaceDepthFailStencilOp(InBackFaceDepthFailStencilOp) , BackFacePassStencilOp(InBackFacePassStencilOp) , StencilReadMask(InStencilReadMask) , StencilWriteMask(InStencilWriteMask) {} friend FArchive& operator<<(FArchive& Ar,FDepthStencilStateInitializerRHI& DepthStencilStateInitializer) { Ar << DepthStencilStateInitializer.bEnableDepthWrite; Ar << DepthStencilStateInitializer.DepthTest; Ar << DepthStencilStateInitializer.bEnableFrontFaceStencil; Ar << DepthStencilStateInitializer.FrontFaceStencilTest; Ar << DepthStencilStateInitializer.FrontFaceStencilFailStencilOp; Ar << DepthStencilStateInitializer.FrontFaceDepthFailStencilOp; Ar << DepthStencilStateInitializer.FrontFacePassStencilOp; Ar << DepthStencilStateInitializer.bEnableBackFaceStencil; Ar << DepthStencilStateInitializer.BackFaceStencilTest; Ar << DepthStencilStateInitializer.BackFaceStencilFailStencilOp; Ar << DepthStencilStateInitializer.BackFaceDepthFailStencilOp; Ar << DepthStencilStateInitializer.BackFacePassStencilOp; Ar << DepthStencilStateInitializer.StencilReadMask; Ar << DepthStencilStateInitializer.StencilWriteMask; return Ar; } RHI_API friend uint32 GetTypeHash(const FDepthStencilStateInitializerRHI& Initializer); RHI_API friend bool operator== (const FDepthStencilStateInitializerRHI& A, const FDepthStencilStateInitializerRHI& B); RHI_API FString ToString() const; RHI_API void FromString(const FString& Src); RHI_API void FromString(const FStringView& Src); }; class FBlendStateInitializerRHI { public: struct FRenderTarget { enum { NUM_STRING_FIELDS = 7 }; TEnumAsByte ColorBlendOp; TEnumAsByte ColorSrcBlend; TEnumAsByte ColorDestBlend; TEnumAsByte AlphaBlendOp; TEnumAsByte AlphaSrcBlend; TEnumAsByte AlphaDestBlend; TEnumAsByte ColorWriteMask; FRenderTarget( EBlendOperation InColorBlendOp = BO_Add, EBlendFactor InColorSrcBlend = BF_One, EBlendFactor InColorDestBlend = BF_Zero, EBlendOperation InAlphaBlendOp = BO_Add, EBlendFactor InAlphaSrcBlend = BF_One, EBlendFactor InAlphaDestBlend = BF_Zero, EColorWriteMask InColorWriteMask = CW_RGBA ) : ColorBlendOp(InColorBlendOp) , ColorSrcBlend(InColorSrcBlend) , ColorDestBlend(InColorDestBlend) , AlphaBlendOp(InAlphaBlendOp) , AlphaSrcBlend(InAlphaSrcBlend) , AlphaDestBlend(InAlphaDestBlend) , ColorWriteMask(InColorWriteMask) {} friend FArchive& operator<<(FArchive& Ar,FRenderTarget& RenderTarget) { Ar << RenderTarget.ColorBlendOp; Ar << RenderTarget.ColorSrcBlend; Ar << RenderTarget.ColorDestBlend; Ar << RenderTarget.AlphaBlendOp; Ar << RenderTarget.AlphaSrcBlend; Ar << RenderTarget.AlphaDestBlend; Ar << RenderTarget.ColorWriteMask; return Ar; } RHI_API FString ToString() const; RHI_API void FromString(const TArray& Parts, int32 Index); RHI_API void FromString(TArrayView Parts); }; FBlendStateInitializerRHI() {} FBlendStateInitializerRHI(const FRenderTarget& InRenderTargetBlendState, bool bInUseAlphaToCoverage = false) : bUseIndependentRenderTargetBlendStates(false) , bUseAlphaToCoverage(bInUseAlphaToCoverage) { RenderTargets[0] = InRenderTargetBlendState; } template FBlendStateInitializerRHI(const TStaticArray& InRenderTargetBlendStates, bool bInUseAlphaToCoverage = false) : bUseIndependentRenderTargetBlendStates(NumRenderTargets > 1) , bUseAlphaToCoverage(bInUseAlphaToCoverage) { static_assert(NumRenderTargets <= MaxSimultaneousRenderTargets, "Too many render target blend states."); for(uint32 RenderTargetIndex = 0;RenderTargetIndex < NumRenderTargets;++RenderTargetIndex) { RenderTargets[RenderTargetIndex] = InRenderTargetBlendStates[RenderTargetIndex]; } } TStaticArray RenderTargets; bool bUseIndependentRenderTargetBlendStates; bool bUseAlphaToCoverage; friend FArchive& operator<<(FArchive& Ar,FBlendStateInitializerRHI& BlendStateInitializer) { Ar << BlendStateInitializer.RenderTargets; Ar << BlendStateInitializer.bUseIndependentRenderTargetBlendStates; Ar << BlendStateInitializer.bUseAlphaToCoverage; return Ar; } RHI_API friend uint32 GetTypeHash(const FBlendStateInitializerRHI::FRenderTarget& RenderTarget); RHI_API friend bool operator== (const FBlendStateInitializerRHI::FRenderTarget& A, const FBlendStateInitializerRHI::FRenderTarget& B); RHI_API friend uint32 GetTypeHash(const FBlendStateInitializerRHI& Initializer); RHI_API friend bool operator== (const FBlendStateInitializerRHI& A, const FBlendStateInitializerRHI& B); RHI_API FString ToString() const; RHI_API void FromString(const FString& Src); RHI_API void FromString(const FStringView& Src); }; /** * Viewport bounds structure to set multiple view ports for the geometry shader * (needs to be 1:1 to the D3D11 structure) */ struct FViewportBounds { float TopLeftX; float TopLeftY; float Width; float Height; float MinDepth; float MaxDepth; FViewportBounds() {} FViewportBounds(float InTopLeftX, float InTopLeftY, float InWidth, float InHeight, float InMinDepth = 0.0f, float InMaxDepth = 1.0f) :TopLeftX(InTopLeftX), TopLeftY(InTopLeftY), Width(InWidth), Height(InHeight), MinDepth(InMinDepth), MaxDepth(InMaxDepth) { } }; struct FVRamAllocation { FVRamAllocation() = default; FVRamAllocation(uint64 InAllocationStart, uint64 InAllocationSize) : AllocationStart(InAllocationStart) , AllocationSize(InAllocationSize) { } bool IsValid() const { return AllocationSize > 0; } // in bytes uint64 AllocationStart{}; // in bytes uint64 AllocationSize{}; }; struct FRHIResourceInfo { FName Name; ERHIResourceType Type{ RRT_None }; FVRamAllocation VRamAllocation; bool IsTransient{ false }; bool bValid{ true }; bool bResident{ true }; }; struct FRHIDispatchIndirectParametersNoPadding { uint32 ThreadGroupCountX; uint32 ThreadGroupCountY; uint32 ThreadGroupCountZ; }; struct FRHIDispatchIndirectParameters : public FRHIDispatchIndirectParametersNoPadding { #if PLATFORM_DISPATCH_INDIRECT_ARGUMENT_BOUNDARY_SIZE == 64 uint32 Padding; // pad to 32 bytes to prevent crossing of 64 byte boundary in ExecuteIndirect calls #elif PLATFORM_DISPATCH_INDIRECT_ARGUMENT_BOUNDARY_SIZE == 128 uint32 Padding[5]; // pad to 64 bytes to prevent crossing of 128 byte boundary in ExecuteIndirect calls #elif PLATFORM_DISPATCH_INDIRECT_ARGUMENT_BOUNDARY_SIZE != 0 #error FRHIDispatchIndirectParameters does not account for PLATFORM_DISPATCH_INDIRECT_ARGUMENT_BOUNDARY_SIZE. #endif }; static_assert(PLATFORM_DISPATCH_INDIRECT_ARGUMENT_BOUNDARY_SIZE == 0 || PLATFORM_DISPATCH_INDIRECT_ARGUMENT_BOUNDARY_SIZE % sizeof(FRHIDispatchIndirectParameters) == 0); struct FRHIDrawIndirectParameters { uint32 VertexCountPerInstance; uint32 InstanceCount; uint32 StartVertexLocation; uint32 StartInstanceLocation; }; struct FRHIDrawIndexedIndirectParameters { uint32 IndexCountPerInstance; uint32 InstanceCount; uint32 StartIndexLocation; int32 BaseVertexLocation; uint32 StartInstanceLocation; }; // RHI base resource types. #include "RHIResources.h" #include "DynamicRHI.h" /** Initializes the RHI. */ extern RHI_API void RHIInit(bool bHasEditorToken); /** Performs additional RHI initialization before the render thread starts. */ extern RHI_API void RHIPostInit(const TArray& InPixelFormatByteWidth); /** Shuts down the RHI. */ extern RHI_API void RHIExit(); // Detect whether the current driver is denylisted and show a message box // prompting to update it if necessary. extern RHI_API void RHIDetectAndWarnOfBadDrivers(bool bHasEditorToken); // Panic delegate is called when when a fatal condition is encountered within RHI function. DECLARE_DELEGATE_OneParam(FRHIPanicEvent, const FName&); extern RHI_API FRHIPanicEvent& RHIGetPanicDelegate(); // Return what the expected number of samplers will be supported by a feature level // Note that since the Feature Level is pretty orthogonal to the RHI/HW, this is not going to be perfect // If should only be used for a guess at the limit, the real limit will not be known until runtime inline uint32 GetExpectedFeatureLevelMaxTextureSamplers(const FStaticFeatureLevel FeatureLevel) { return 16; } RHI_API bool RHIGetShaderPlatformConfigurationInt(int32& OutSetting, FConfigCacheIni* Config, EShaderPlatform Platform, const TCHAR* SettingName); RHI_API bool RHIGetShaderPlatformConfigurationString(FString& OutSetting, FConfigCacheIni* Config, EShaderPlatform Platform, const TCHAR* SettingName); RHI_API TOptional RHIGetForcedBindlessConfiguration(); RHI_API ERHIBindlessConfiguration RHIParseBindlessConfiguration(EShaderPlatform Platform, const FString& ConfigSetting, const FString& CvarSetting); RHI_API ERHIBindlessConfiguration RHIGetRuntimeBindlessConfiguration(EShaderPlatform Platform); UE_DEPRECATED(5.7, "RHIGetRuntimeBindlessConfiguration should be used") inline ERHIBindlessConfiguration RHIGetRuntimeBindlessResourcesConfiguration(EShaderPlatform Platform) { return RHIGetRuntimeBindlessConfiguration(Platform); } UE_DEPRECATED(5.7, "RHIGetRuntimeBindlessConfiguration should be used") inline ERHIBindlessConfiguration RHIGetRuntimeBindlessSamplersConfiguration(EShaderPlatform Platform) { return RHIGetRuntimeBindlessConfiguration(Platform); }