Files
UnrealEngine/Engine/Shaders/Public/Platform.ush
2025-05-18 13:04:45 +08:00

1458 lines
43 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
Prefix.usf: USF file automatically included by shader preprocessor.
=============================================================================*/
#pragma once
#include "FP16Math.ush"
// Values of FEATURE_LEVEL.
#define FEATURE_LEVEL_ES2_REMOVED 1
#define FEATURE_LEVEL_ES3_1 2
#define FEATURE_LEVEL_SM3 3
#define FEATURE_LEVEL_SM4 4
#define FEATURE_LEVEL_SM5 5
#define FEATURE_LEVEL_SM6 6
#define FEATURE_LEVEL_MAX 7
// Values of PLATFORM_GPU_ARCH
#define PLATFORM_GPU_ARCH_UNKNOWN 0x0000
#define PLATFORM_GPU_ARCH_AMD 0x1000
#define PLATFORM_GPU_ARCH_AMD_GCN_1 0x1010
#define PLATFORM_GPU_ARCH_AMD_GCN_2 0x1020
#define PLATFORM_GPU_ARCH_AMD_GCN_3 0x1030
#define PLATFORM_GPU_ARCH_AMD_GCN_4 0x1040
#define PLATFORM_GPU_ARCH_AMD_GCN_5 0x1050
#define PLATFORM_GPU_ARCH_AMD_RDNA_1 0x1110
#define PLATFORM_GPU_ARCH_AMD_RDNA_2 0x1120
#define PLATFORM_GPU_ARCH_AMD_RDNA_3 0x1130
#define PLATFORM_GPU_ARCH_AMD_LATTEST PLATFORM_GPU_ARCH_AMD_RDNA_3
#define PLATFORM_GPU_ARCH_NVIDIA 0x2000
#define PLATFORM_GPU_ARCH_NVIDIA_KEPLER 0x2010
#define PLATFORM_GPU_ARCH_NVIDIA_MAXWELL 0x2020
#define PLATFORM_GPU_ARCH_NVIDIA_PASCAL 0x2030
#define PLATFORM_GPU_ARCH_NVIDIA_VOLTA 0x2040
#define PLATFORM_GPU_ARCH_NVIDIA_TURING 0x2050
#define PLATFORM_GPU_ARCH_NVIDIA_AMPERE 0x2060
#define PLATFORM_GPU_ARCH_NVIDIA_ADA 0x2070
#define PLATFORM_GPU_ARCH_NVIDIA_LATTEST PLATFORM_GPU_ARCH_NVIDIA_ADA
#define PLATFORM_GPU_ARCH_INTEL 0x3000
#define PLATFORM_GPU_ARCH_INTEL_ARC 0x3010
#define PLATFORM_GPU_ARCH_INTEL_LATTEST PLATFORM_GPU_ARCH_INTEL_ARC
// ---------------------------------------------------- Profile or compiler specific includes
// TODO: Have shader compiler including these platform specific USF files, that needs to work
// with ShaderCore.cpp's GetShaderIncludes().
#ifdef OVERRIDE_PLATFORMCOMMON_USH
#include "/Platform/Public/PlatformCommon.ush"
#elif COMPILER_METAL
// Helps with iteration when changing Metal shader code generation backend.
#include "Platform/Metal/MetalCommon.ush"
#elif COMPILER_VULKAN
// Helps with iteration when changing Vulkan shader code generation backend.
#include "Platform/Vulkan/VulkanCommon.ush"
#elif COMPILER_GLSL || COMPILER_GLSL_ES3_1
// Helps with iteration when changing Vulkan shader code generation backend.
#include "Platform/GL/GLCommon.ush"
#elif SM6_PROFILE || SM5_PROFILE
#include "Platform/D3D/D3DCommon.ush"
#endif
#include "/Engine/Public/BindlessResources.ush"
#include "/Engine/Public/OverloadMacros.ush"
// ---------------------------------------------------- DDC invalidation
// to support the console command "r.InvalidateShaderCache"
#include "ShaderVersion.ush"
// ---------------------------------------------------- COMPILE_* and *_PROFILE defaults
#ifndef COMPILER_HLSLCC
#define COMPILER_HLSLCC 0
#endif
#ifndef COMPILER_DXC
#define COMPILER_DXC 0
#endif
#ifndef COMPILER_FXC
#define COMPILER_FXC 0
#endif
#ifndef COMPILER_HLSL
#define COMPILER_HLSL 0
#endif
#ifndef COMPILER_PSSL
#define COMPILER_PSSL 0
#endif
#ifndef COMPILER_GLSL
#define COMPILER_GLSL 0
#endif
#ifndef COMPILER_GLSL_ES3_1
#define COMPILER_GLSL_ES3_1 0
#endif
#ifndef COMPILER_METAL
#define COMPILER_METAL 0
#endif
#ifndef COMPILER_SUPPORTS_ATTRIBUTES
#define COMPILER_SUPPORTS_ATTRIBUTES 0
#endif
#ifndef COMPILER_SUPPORTS_QUAD_PASS
#define COMPILER_SUPPORTS_QUAD_PASS 0
#endif
#ifndef COMPILER_SUPPORTS_DUAL_SOURCE_BLENDING_SLOT_DECORATION
#define COMPILER_SUPPORTS_DUAL_SOURCE_BLENDING_SLOT_DECORATION 0
#endif
#ifndef COMPILER_SUPPORTS_PRIMITIVE_SHADERS
#define COMPILER_SUPPORTS_PRIMITIVE_SHADERS 0
#endif
#ifndef COMPILER_SUPPORTS_BARYCENTRIC_INTRINSICS
#define COMPILER_SUPPORTS_BARYCENTRIC_INTRINSICS 0
#endif
// Whether the shader compiler supports WAVESIZE()
#ifndef COMPILER_SUPPORTS_WAVE_SIZE
#define COMPILER_SUPPORTS_WAVE_SIZE 0
#endif
#ifndef COMPILER_FORCE_WAVE32_MODE
#define COMPILER_FORCE_WAVE32_MODE
#endif
#ifndef COMPILER_ALLOW_CS_DERIVATIVES
#define COMPILER_ALLOW_CS_DERIVATIVES
#endif
#ifndef PLATFORM_REQUIRES_UNWRAPPED_MESH_SHADER_ARGS
#define PLATFORM_REQUIRES_UNWRAPPED_MESH_SHADER_ARGS 0
#endif
#ifndef COMPILER_SUPPORTS_TYPEDSTORE
#define COMPILER_SUPPORTS_TYPEDSTORE 0
#endif
#ifndef PLATFORM_SUPPORTS_ROV
#define PLATFORM_SUPPORTS_ROV 0
#endif
#if !PLATFORM_SUPPORTS_ROV
#define RasterizerOrderedTexture2D RWTexture2D
#endif
#ifndef SM6_PROFILE
#define SM6_PROFILE 0
#endif
#ifndef SM5_PROFILE
#define SM5_PROFILE 0
#endif
#ifndef OPENGL_PROFILE
#define OPENGL_PROFILE 0
#endif
#ifndef ES3_1_PROFILE
#define ES3_1_PROFILE 0
#endif
#ifndef METAL_ES3_1_PROFILE
#define METAL_ES3_1_PROFILE 0
#endif
// Deprecated, use METAL_ES3_1_PROFILE instead
#ifndef METAL_PROFILE
#define METAL_PROFILE METAL_ES3_1_PROFILE
#endif
#ifndef METAL_SM5_IOS_TVOS_PROFILE
#define METAL_SM5_IOS_TVOS_PROFILE 0
#endif
// Deprecated, use METAL_SM5_IOS_TVOS_PROFILE instead
#ifndef METAL_MRT_PROFILE
#define METAL_MRT_PROFILE METAL_SM5_IOS_TVOS_PROFILE
#endif
#ifndef METAL_SM5_PROFILE
#define METAL_SM5_PROFILE 0
#endif
#ifndef METAL_SM6_PROFILE
#define METAL_SM6_PROFILE 0
#endif
#ifndef COMPILER_VULKAN
#define COMPILER_VULKAN 0
#endif
#ifndef VULKAN_PROFILE
#define VULKAN_PROFILE 0
#endif
#ifndef VULKAN_PROFILE_SM5
#define VULKAN_PROFILE_SM5 0
#endif
#ifndef VULKAN_PROFILE_SM6
#define VULKAN_PROFILE_SM6 0
#endif
#ifndef IOS
#define IOS 0
#endif
#ifndef MAC
#define MAC 0
#endif
#ifndef VECTORVM_PROFILE
#define VECTORVM_PROFILE 0
#endif
#ifndef IR_LANGUAGE_DXBC
#define IR_LANGUAGE_DXBC 0
#endif
// 'static' asserts
#if COMPILER_GLSL || COMPILER_GLSL_ES3_1 || COMPILER_VULKAN || COMPILER_METAL
#if !COMPILER_HLSLCC
#error "Missing COMPILER_HLSLCC define!"
#endif
#endif
#ifndef PLATFORM_SUPPORTS_CALLABLE_SHADERS
#define PLATFORM_SUPPORTS_CALLABLE_SHADERS 0
#endif
// Whether the platforms support official SM6 wave intrinsics
// https://github.com/Microsoft/DirectXShaderCompiler/wiki/Wave-Intrinsics
#ifndef PLATFORM_SUPPORTS_SM6_0_WAVE_OPERATIONS
#define PLATFORM_SUPPORTS_SM6_0_WAVE_OPERATIONS 0
#endif
#ifndef PLATFORM_SUPPORTS_REAL_TYPES
#define PLATFORM_SUPPORTS_REAL_TYPES 0
#endif
#ifndef COMPILER_SUPPORTS_WAVE_32_64_MODE
#define COMPILER_SUPPORTS_WAVE_32_64_MODE 0
#endif
//Platforms that don't run the editor shouldn't need editor features in the shaders.
#ifndef PLATFORM_SUPPORTS_EDITOR_SHADERS
#define PLATFORM_SUPPORTS_EDITOR_SHADERS 1
#endif
#ifndef COMPILER_SUPPORTS_HLSL2021
#define COMPILER_SUPPORTS_HLSL2021 0
#endif
#ifndef PLATFORM_SUPPORTS_CONSTANTBUFFER_OBJECT
#define PLATFORM_SUPPORTS_CONSTANTBUFFER_OBJECT 0
#endif
#ifndef PLATFORM_SUPPORTS_UNIFORM_BUFFER_OBJECTS
#define PLATFORM_SUPPORTS_UNIFORM_BUFFER_OBJECTS 0
#endif
#ifndef PLATFORM_GPU_ARCH
#define PLATFORM_GPU_ARCH PLATFORM_GPU_ARCH_UNKNOWN
#endif
#ifndef PLATFORM_NEEDS_DEPTH_TEXTURE_READS
#define PLATFORM_NEEDS_DEPTH_TEXTURE_READS 0
#endif
#ifndef PLATFORM_NEEDS_SELECT_UINT
#define PLATFORM_NEEDS_SELECT_UINT 0
#endif
#ifndef PLATFORM_NEEDS_SEPARATE_SHADOW_DEPTH_CUBE_TEXTURE
#define PLATFORM_NEEDS_SEPARATE_SHADOW_DEPTH_CUBE_TEXTURE 0
#endif
#ifndef PLATFORM_SUPPORTS_SUBSTRATE_UINT1
#define PLATFORM_SUPPORTS_SUBSTRATE_UINT1 1
#endif
#ifndef COMPILER_NEEDS_DETERMINANT
#define COMPILER_NEEDS_DETERMINANT 0
#endif
#if COMPILER_DXC == 1
#define SHADER_PUSH_WARNINGS_STATE _Pragma("dxc diagnostic push")
#define SHADER_POP_WARNINGS_STATE _Pragma("dxc diagnostic pop")
// DXC requires several pragmas because there isn't a warning group that covers all cases
#define SHADER_DISABLE_WARNINGS \
_Pragma("dxc diagnostic ignored \"-Wall\"") \
_Pragma("dxc diagnostic ignored \"-Wconversion\"") \
_Pragma("dxc diagnostic ignored \"-Wfor-redefinition\"") \
_Pragma("dxc diagnostic ignored \"-Winline-asm\"") \
_Pragma("dxc diagnostic ignored \"-Wunsequenced\"")
#endif
// If the shader compiler does not suport disabling warnings locally, these macros will be empty
#ifndef SHADER_DISABLE_WARNINGS
#define SHADER_DISABLE_WARNINGS
#endif
#ifndef SHADER_PUSH_WARNINGS_STATE
#define SHADER_PUSH_WARNINGS_STATE
#endif
#ifndef SHADER_POP_WARNINGS_STATE
#define SHADER_POP_WARNINGS_STATE
#endif
// ---------------------------------------------------- Alternative floating point types
#ifndef FORCE_FLOATS
#define FORCE_FLOATS 0
#endif
#if COMPILER_DXC && !FORCE_FLOATS && (ES3_1_PROFILE || METAL_ES3_1_PROFILE || VULKAN_PROFILE_SM5)
#pragma dxc diagnostic ignored "-Wconversion"
#endif
#if ES3_1_PROFILE && MOBILE_EMULATION && !FORCE_FLOATS
#define half min16float
#define half1 min16float1
#define half2 min16float2
#define half3 min16float3
#define half4 min16float4
#define half3x3 min16float3x3
#define half3x4 min16float3x4
#define half4x4 min16float4x4
#elif ((!(ES3_1_PROFILE || METAL_ES3_1_PROFILE || VULKAN_PROFILE_SM5)) && !PLATFORM_SUPPORTS_REAL_TYPES) || FORCE_FLOATS
// Always use floats when using the ES3/METAL compiler, because platforms not optimized for lower precision,
// And we don't want potential side effects on other platforms
#define half float
#define half1 float1
#define half2 float2
#define half3 float3
#define half4 float4
#define half3x3 float3x3
#define half4x4 float4x4
#define half4x3 float4x3
#define fixed float
#define fixed1 float1
#define fixed2 float2
#define fixed3 float3
#define fixed4 float4
#define fixed3x3 float3x3
#define fixed4x4 float4x4
#define fixed4x3 float4x3
#elif (VULKAN_PROFILE || VULKAN_PROFILE_SM5) || (COMPILER_GLSL_ES3_1 && !(COMPILER_HLSLCC && COMPILER_HLSLCC == 1))
// For VULKAN and OPENGL ES31 use RelaxedPrecision for half floats
#define half min16float
#define half2 min16float2
#define half3 min16float3
#define half4 min16float4
#define half3x3 min16float3x3
#define half3x4 min16float3x4
#define half4x4 min16float4x4
#endif
// ---------------------------------------------------- Profile config
#if SM6_PROFILE
// SM6 = full dx12 features (high end UE5 rendering)
#define FEATURE_LEVEL FEATURE_LEVEL_SM6
#elif SM5_PROFILE
// SM5 = full dx11 features (high end UE4 rendering)
#define FEATURE_LEVEL FEATURE_LEVEL_SM5
#elif SWITCH_PROFILE || SWITCH_PROFILE_FORWARD
#undef ES3_1_PROFILE
#if SWITCH_PROFILE
#define FEATURE_LEVEL FEATURE_LEVEL_SM5
#else
#define FEATURE_LEVEL FEATURE_LEVEL_ES3_1
// @todo switch: maybe all uses of this should check feature level not profile?
#define ES3_1_PROFILE 1
#endif
#elif VULKAN_PROFILE
#define FEATURE_LEVEL FEATURE_LEVEL_ES3_1
// @todo: replace usage of ES3_1_PROFILE with FEATURE_LEVEL where appropriate
#undef ES3_1_PROFILE
#define ES3_1_PROFILE 1
#elif VULKAN_PROFILE_SM5
#define FEATURE_LEVEL FEATURE_LEVEL_SM5
#define STENCIL_COMPONENT_SWIZZLE .x
#elif VULKAN_PROFILE_SM6
#define FEATURE_LEVEL FEATURE_LEVEL_SM6
#define STENCIL_COMPONENT_SWIZZLE .x
#elif METAL_ES3_1_PROFILE
#define FEATURE_LEVEL FEATURE_LEVEL_ES3_1
// @todo metal: remove this and make sure all uses handle METAL_ES3_1_PROFILE
#undef ES3_1_PROFILE
#define ES3_1_PROFILE 1
#define FCOLOR_COMPONENT_SWIZZLE .rgba
#define FMANUALFETCH_COLOR_COMPONENT_SWIZZLE .bgra
#define STENCIL_COMPONENT_SWIZZLE .x
#elif METAL_SM5_IOS_TVOS_PROFILE
#define FEATURE_LEVEL FEATURE_LEVEL_SM5
#define FCOLOR_COMPONENT_SWIZZLE .rgba
#define FMANUALFETCH_COLOR_COMPONENT_SWIZZLE .bgra
#define STENCIL_COMPONENT_SWIZZLE .x
#elif METAL_SM5_PROFILE
#define FEATURE_LEVEL FEATURE_LEVEL_SM5
#define FCOLOR_COMPONENT_SWIZZLE .rgba
#define FMANUALFETCH_COLOR_COMPONENT_SWIZZLE .bgra
#define STENCIL_COMPONENT_SWIZZLE .x
#elif METAL_SM6_PROFILE
#define FEATURE_LEVEL FEATURE_LEVEL_SM6
#define FCOLOR_COMPONENT_SWIZZLE .rgba
#define FMANUALFETCH_COLOR_COMPONENT_SWIZZLE .bgra
#define STENCIL_COMPONENT_SWIZZLE .x
#elif ES3_1_PROFILE
#define FEATURE_LEVEL FEATURE_LEVEL_ES3_1
#if COMPILER_GLSL_ES3_1
#define FCOLOR_COMPONENT_SWIZZLE .bgra
#define FMANUALFETCH_COLOR_COMPONENT_SWIZZLE .bgra
#else
#define FCOLOR_COMPONENT_SWIZZLE .rgba
#define FMANUALFETCH_COLOR_COMPONENT_SWIZZLE .bgra
#endif
#if COMPILER_GLSL || COMPILER_GLSL_ES3_1
// A8 textures when sampled have their component in R
#define A8_SAMPLE_MASK .r
#endif
#elif VECTORVM_PROFILE
#define FEATURE_LEVEL FEATURE_LEVEL_SM5
#endif
#ifndef FEATURE_LEVEL
#error FEATURE_LEVEL has not been defined for this platform. Add it to Platform.ush or in the Common.ush file for this platform
#define FEATURE_LEVEL FEATURE_LEVEL_MAX
#endif
#if COMPILER_METAL
// Metal does not allow writes to A8 textures so we are faking it by making them all R8.
// WARNING: If this changes or the type in MetalRHI changes both must be updated!
#define A8_SAMPLE_MASK .r
#endif
// ---------------------------------------------------- Swizzle defaults
// If we didn't request color component swizzling, just make it empty
#ifndef FCOLOR_COMPONENT_SWIZZLE
#define FCOLOR_COMPONENT_SWIZZLE .rgba
#endif
#ifndef FMANUALFETCH_COLOR_COMPONENT_SWIZZLE
#define FMANUALFETCH_COLOR_COMPONENT_SWIZZLE .bgra
#endif
#ifndef STENCIL_COMPONENT_SWIZZLE
#define STENCIL_COMPONENT_SWIZZLE .g
#endif
#ifndef A8_SAMPLE_MASK
#define A8_SAMPLE_MASK .a
#endif
// ---------------------------------------------------- Platform dependent supports
// Type macros for Uniform Buffer code generation.
// Hides the platform specific 'half' and 'fixed' support but has to extend to all types and dimensions
#if (FEATURE_LEVEL == FEATURE_LEVEL_ES3_1)
#define UB_INT(Dim) int##Dim
#define UB_UINT(Dim) uint##Dim
#define UB_FLOAT(Dim) float##Dim
#if METAL_ES3_1_PROFILE || COMPILER_HLSL
#define UB_HALF_FLOAT(Dim) float##Dim
#else
#define UB_HALF_FLOAT(Dim) half##Dim
#endif
#define UB_FIXED_FLOAT(Dim) fixed##Dim
#else
#define UB_INT(Dim) int##Dim
#define UB_UINT(Dim) uint##Dim
#define UB_FLOAT(Dim) float##Dim
#define UB_HALF_FLOAT(Dim) float##Dim
#define UB_FIXED_FLOAT(Dim) float##Dim
#endif
// 16KB by default. Must match Platform.h
#ifndef PLATFORM_MAX_UNIFORM_BUFFER_RANGE
#define PLATFORM_MAX_UNIFORM_BUFFER_RANGE (16u*1024u)
#endif
#define PLATFORM_MAX_UNIFORM_BUFFER_RANGE_FLOAT4 (PLATFORM_MAX_UNIFORM_BUFFER_RANGE/16u)
#if PLATFORM_SUPPORTS_CONSTANTBUFFER_OBJECT
#define UB_CB_DEFINITION_START( UBName ) struct F##UBName##Constants {
#define UB_CB_MEMBER_NAME( UBName, MemberName) MemberName
#define UB_CB_PREFIXED_MEMBER_NAME( UBName, Prefix, MemberName) Prefix##MemberName
#define UB_CB_DEFINITION_END( UBName ) }; ConstantBuffer<F##UBName##Constants> UBName;
#define UB_CB_MEMBER_ACCESS( UBName, MemberName) UBName##.##MemberName
#define UB_CB_PREFIXED_MEMBER_ACCESS(UBName, Prefix, MemberName) UBName##.##Prefix##MemberName
#define UB_DECL_PARAMETER(UBName, StructName, GlobalName) UBName##.##StructName = UBName##.##GlobalName
#define UB_DECL_RESOURCE(UBName, StructName, GlobalName) UBName##.##StructName = UBName##_##GlobalName
#else
#define UB_CB_DEFINITION_START( UBName ) cbuffer UBName {
#define UB_STATIC_CB_DEFINITION_START(UBName, ResourceIndex, Space) cbuffer UBName : register(b##ResourceIndex, space##Space) {
#define UB_CB_MEMBER_NAME( UBName, MemberName) UBName##_##MemberName
#define UB_CB_PREFIXED_MEMBER_NAME( UBName, Prefix, MemberName) Prefix##UBName##_##MemberName
#define UB_CB_DEFINITION_END( UBName ) }
#define UB_CB_MEMBER_ACCESS( UBName, MemberName) UBName##_##MemberName
#define UB_CB_PREFIXED_MEMBER_ACCESS(UBName, Prefix, MemberName) Prefix##UBName##_##MemberName
#define UB_DECL_PARAMETER(UBName, StructName, GlobalName) UBName##.##StructName = UBName##_##GlobalName
#define UB_DECL_RESOURCE(UBName, StructName, GlobalName) UBName##.##StructName = UBName##_##GlobalName
#endif
#define UB_CB_UNIFORM_BLOCK(UBName, MemberName) UB_FLOAT(4) UB_CB_MEMBER_NAME(UBName,MemberName)[PLATFORM_MAX_UNIFORM_BUFFER_RANGE_FLOAT4]
// Use interpolator for platforms that do not support ClipDistance
#if !PLATFORM_SUPPORTS_CLIP_DISTANCE
#define SV_ClipDistance OUTCLIPDIST
#endif
// non-editor platforms generally never want development/editor features.
#ifndef PLATFORM_SUPPORTS_DEVELOPMENT_SHADERS
#define PLATFORM_SUPPORTS_DEVELOPMENT_SHADERS 1
#endif
#ifndef MOBILE_EMULATION
#define MOBILE_EMULATION 0
#endif
// Whether the platform supports independent texture and samplers (defined in DDSPI)
// When enabled, different texture lookups can share samplers to allow more artist samplers in the base pass
// Ideally this would just be enabled for all SM4 and above feature level platforms
#ifndef SUPPORTS_INDEPENDENT_SAMPLERS
#define SUPPORTS_INDEPENDENT_SAMPLERS 0
#endif
// Whether the platform support pixel coverage on MSAA targets (SV_Coverage).
#define SUPPORTS_PIXEL_COVERAGE (FEATURE_LEVEL >= FEATURE_LEVEL_SM5 && !COMPILER_GLSL && !MOBILE_EMULATION)
// Must match C++ RHISupports4ComponentUAVReadWrite
// D3D11 does not support multi-component loads from a UAV: "error X3676: typed UAV loads are only allowed for single-component 32-bit element types"
#ifndef PLATFORM_SUPPORTS_4COMPONENT_UAV_READ_WRITE
#define PLATFORM_SUPPORTS_4COMPONENT_UAV_READ_WRITE (XBOXONE_PROFILE || COMPILER_METAL)
#endif
// Whether the platform supports binding SRVs to the vertex shader stage.
// This is generally available on high-end platforms and not available on mobile outside of some exceptions.
// The real value is expected to be set based on DataDrivenShaderPlatformInfo in GlobalBeginCompileShader().
#ifndef PLATFORM_SUPPORTS_VERTEX_SHADER_SRVS
#define PLATFORM_SUPPORTS_VERTEX_SHADER_SRVS 1
#endif
// Whether the platform supports binding UAVs to the vertex shader stage.
#ifndef PLATFORM_SUPPORTS_VERTEX_SHADER_UAVS
#define PLATFORM_SUPPORTS_VERTEX_SHADER_UAVS 0
#endif
// ---------------------------------------------------- Compiler specific defaults and fallbacks
#if !defined(PLATFORM_BREAK)
#define PLATFORM_BREAK()
#endif
#if !defined(PLATFORM_ASSERT)
#define PLATFORM_ASSERT(condition, assert_id)
#define PLATFORM_ASSERT1(condition, assert_id, a)
#define PLATFORM_ASSERT2(condition, assert_id, a, b)
#define PLATFORM_ASSERT3(condition, assert_id, a, b, c)
#define PLATFORM_ASSERT4(condition, assert_id, a, b, c, d)
#endif
#if !defined(PLATFORM_SUPPORTS_SHADER_TIMESTAMP)
#if USE_NVAPI_TIMESTAMP
#include "/Engine/Shared/ThirdParty/NVIDIA/nvHLSLExtns.h"
#define PLATFORM_SUPPORTS_SHADER_TIMESTAMP 1
#define FTimestamp uint
FTimestamp GetShaderTimestamp()
{
return NvGetSpecial( NV_SPECIALOP_GLOBAL_TIMER_LO );
}
uint ShaderTimestampDiff(FTimestamp TimeBegin, FTimestamp TimeEnd)
{
// Account for (at most one) overflow
return TimeEnd >= TimeBegin ? (TimeEnd - TimeBegin) : (~0u - (TimeBegin - TimeEnd));
}
#else // !USE_NVAPI_TIMESTAMP
#define PLATFORM_SUPPORTS_SHADER_TIMESTAMP 0
#endif // !USE_NVAPI_TIMESTAMP
#endif // !defined(PLATFORM_SUPPORTS_SHADER_TIMESTAMP)
// Hlslcc platforms ignore the uniform keyword as it can't properly optimize flow
#if COMPILER_HLSLCC
#define uniform
#endif
#if PLATFORM_SUPPORTS_SM6_0_WAVE_OPERATIONS
#if !defined(COMPILER_SUPPORTS_WAVE_ONCE)
#define COMPILER_SUPPORTS_WAVE_ONCE 1
#endif
#if !defined(COMPILER_SUPPORTS_WAVE_VOTE)
#define COMPILER_SUPPORTS_WAVE_VOTE 1
#endif
#if !defined(COMPILER_SUPPORTS_WAVE_MINMAX)
#define COMPILER_SUPPORTS_WAVE_MINMAX 1
#endif
#if !defined(COMPILER_SUPPORTS_WAVE_BIT_ORAND)
#define COMPILER_SUPPORTS_WAVE_BIT_ORAND 1
#endif
#endif
// If compiler lane management in a wave.
// WaveGetLaneCount()
// WaveGetLaneIndex()
// if (WaveIsFirstLane()) { ... }
#ifndef COMPILER_SUPPORTS_WAVE_ONCE
#define COMPILER_SUPPORTS_WAVE_ONCE 0
#endif
// Whether the compiler exposes voting on all lanes:
// WaveActiveAnyTrue(MyBool)
// WaveActiveAnyTrue(MyBool)
// WaveActiveAllEqual(MyBool)
#ifndef COMPILER_SUPPORTS_WAVE_VOTE
#define COMPILER_SUPPORTS_WAVE_VOTE 0
#endif
// Whether the compiler exposes min max instructions across all lane of the wave.
// WaveActiveMin(MyFloat)
// WaveActiveMin(MyInt)
// WaveActiveMin(MyUint)
// WaveActiveMax(MyFloat)
// WaveActiveMax(MyInt)
// WaveActiveMax(MyUint)
#ifndef COMPILER_SUPPORTS_WAVE_MINMAX
#define COMPILER_SUPPORTS_WAVE_MINMAX 0
#endif
// Whether the compiler exposes OR and AND bit operation all lanes:
// WaveActiveBitAnd(MyMask)
// WaveActiveBitOr(MyMask)
#ifndef COMPILER_SUPPORTS_WAVE_BIT_ORAND
#define COMPILER_SUPPORTS_WAVE_BIT_ORAND 0
#endif
// Whether the compiler exposes GCN's ds_swizzle_b32 instruction.
// float WaveLaneSwizzleGCN(float x, const uint and_mask, const uint or_mask, const uint xor_mask)
#ifndef COMPILER_SUPPORTS_WAVE_SWIZZLE_GCN
#define COMPILER_SUPPORTS_WAVE_SWIZZLE_GCN 0
#endif
#ifndef COMPILER_SUPPORTS_WAVE_PERMUTE
#define COMPILER_SUPPORTS_WAVE_PERMUTE 0
#endif
// Mirrors GRHISupportsPrimitiveShaders.
#ifndef COMPILER_SUPPORTS_PRIMITIVE_SHADERS
#define COMPILER_SUPPORTS_PRIMITIVE_SHADERS 0
#endif
// Mirrors GRHISupportsRectTopology.
#ifndef PLATFORM_SUPPORTS_RECT_LIST
#define PLATFORM_SUPPORTS_RECT_LIST 0
#endif
// Mirrors GRHISupportsAtomicUInt64.
#ifndef PLATFORM_SUPPORTS_ATOMIC_UINT64
#define PLATFORM_SUPPORTS_ATOMIC_UINT64 0
#endif
// Support for depth test running both before and after pixel shader
#ifndef COMPILER_SUPPORTS_DEPTHSTENCIL_EARLYTEST_LATEWRITE
#define COMPILER_SUPPORTS_DEPTHSTENCIL_EARLYTEST_LATEWRITE 0
#endif
#ifndef COMPILER_SUPPORTS_SHADER_YIELD
#define COMPILER_SUPPORTS_SHADER_YIELD 0
void ShaderYield()
{
// Do nothing
}
#endif
#ifndef COMPILER_SUPPORTS_GATHER_LOD_RED
#define COMPILER_SUPPORTS_GATHER_LOD_RED 0
#endif
#ifndef COMPILER_SUPPORTS_GATHER_UINT
#define COMPILER_SUPPORTS_GATHER_UINT 0
#endif
#ifndef COMPILER_SUPPORTS_MED3
#define COMPILER_SUPPORTS_MED3 0
#endif
#if (ES3_1_PROFILE && !METAL_ES3_1_PROFILE) || VULKAN_PROFILE_SM5
#define HALF_TYPE half
#define HALF2_TYPE half2
#define HALF3_TYPE half3
#define HALF4_TYPE half4
#else
#define HALF_TYPE float
#define HALF2_TYPE float2
#define HALF3_TYPE float3
#define HALF4_TYPE float4
#endif
// ---------------------------------------------------- Compiler attributes
#if SM6_PROFILE || SM5_PROFILE || COMPILER_SUPPORTS_ATTRIBUTES
/** Avoids flow control constructs. */
#define UNROLL [unroll]
#define UNROLL_N(N) [unroll(N)]
/** Gives preference to flow control constructs. */
#define LOOP [loop]
/** Performs branching by using control flow instructions like jmp and label. */
#define BRANCH [branch]
/** Performs branching by using the cnd instructions. */
#define FLATTEN [flatten]
/** Allows a compute shader loop termination condition to be based off of a UAV read. The loop must not contain synchronization intrinsics. */
#define ALLOW_UAV_CONDITION [allow_uav_condition]
#endif // SM6_PROFILE || SM5_PROFILE || COMPILER_SUPPORTS_ATTRIBUTES
#if SM6_PROFILE || SM5_PROFILE || METAL_SM5_IOS_TVOS_PROFILE || METAL_SM5_PROFILE || METAL_SM6_PROFILE || ES3_1_PROFILE || VULKAN_PROFILE_SM5 || VULKAN_PROFILE_SM6
#define EARLYDEPTHSTENCIL [earlydepthstencil]
#endif
#if COMPILER_SUPPORTS_DUAL_SOURCE_BLENDING_SLOT_DECORATION
#define DUAL_SOURCE_BLENDING_SLOT(SLOT) [[vk::location(0), vk::index(SLOT)]]
#endif
// ---------------------------------------------------- Compiler attribute fallbacks
#ifndef UNROLL
#define UNROLL
#endif
#ifndef UNROLL_N
#define UNROLL_N(N)
#endif
#ifndef LOOP
#define LOOP
#endif
#ifndef BRANCH
#define BRANCH
#endif
#ifndef FLATTEN
#define FLATTEN
#endif
#ifndef ALLOW_UAV_CONDITION
#define ALLOW_UAV_CONDITION
#endif
#ifndef INVARIANT
precise float MakePrecise(in precise float v) { precise float pv = v; return pv; }
precise float2 MakePrecise(in precise float2 v) { precise float2 pv = v; return pv; }
precise float3 MakePrecise(in precise float3 v) { precise float3 pv = v; return pv; }
precise float4 MakePrecise(in precise float4 v) { precise float4 pv = v; return pv; }
#define INVARIANT(X) MakePrecise(X)
#endif
#ifndef INVARIANT_ADD
#define INVARIANT_ADD(Lhs, Rhs) INVARIANT((Lhs) + (Rhs))
#endif
#ifndef INVARIANT_SUB
#define INVARIANT_SUB(Lhs, Rhs) INVARIANT((Lhs) - (Rhs))
#endif
#ifndef INVARIANT_MUL
#define INVARIANT_MUL(Lhs, Rhs) INVARIANT((Lhs) * (Rhs))
#endif
#ifndef INVARIANT_DIV
#define INVARIANT_DIV(Lhs, Rhs) INVARIANT((Lhs) / (Rhs))
#endif
#ifndef INVARIANT_FMA
#define INVARIANT_FMA(A, B, C) INVARIANT(FMA((A), (B), (C)))
#endif
#ifndef INVARIANT_OUTPUT
#define INVARIANT_OUTPUT
#endif
#ifndef PLATFORM_SUPPORTS_FMA
#define PLATFORM_SUPPORTS_FMA 1
#define FMA(a, b, c) mad(a, b, c)
#endif
#ifndef ENABLE_RE_Z
#define ENABLE_RE_Z
#endif
#ifndef COMPILER_SUPPORTS_NOINLINE
#define COMPILER_SUPPORTS_NOINLINE 0
#endif
// Informs compiler we want a subroutine created, which can be used to
// decrease register pressure in certain situations. Code is kept separate,
// and a set number of registers are used on each call. Should only be used
// with extensive profiling, as the default inlining behavior is usually best.
// DXIL: https://github.com/microsoft/DirectXShaderCompiler/blob/master/tools/clang/test/HLSLFileCheck/hlsl/functions/attribute/noinline.hlsl
// SPIRV: https://www.khronos.org/registry/spir-v/specs/unified1/SPIRV.html (DontInline)
#if COMPILER_SUPPORTS_NOINLINE
#define NOINLINE [noinline]
#else
#define NOINLINE
#endif
#ifndef EARLYDEPTHSTENCIL
#define EARLYDEPTHSTENCIL
#endif
#ifndef DUAL_SOURCE_BLENDING_SLOT
#define DUAL_SOURCE_BLENDING_SLOT(SLOT)
#endif
#ifndef DEPTHSTENCIL_EARLYTEST_LATEWRITE
#define DEPTHSTENCIL_EARLYTEST_LATEWRITE
#endif
#ifndef STRONG_TYPE
#define STRONG_TYPE
#endif
#ifndef StrongTypedBuffer
#define StrongTypedBuffer Buffer
#endif
#ifndef RWCoherentBuffer
#define RWCoherentBuffer(TYPE) globallycoherent RWBuffer<TYPE>
#endif
#ifndef RWCoherentStructuredBuffer
#define RWCoherentStructuredBuffer(TYPE) globallycoherent RWStructuredBuffer<TYPE>
#endif
// Drops globallycoherent qualifier when used in a struct
#ifndef RWCoherentStructuredBufferRef
#define RWCoherentStructuredBufferRef(TYPE) RWStructuredBuffer<TYPE>
#endif
#ifndef RWCoherentByteAddressBuffer
#define RWCoherentByteAddressBuffer globallycoherent RWByteAddressBuffer
#endif
// Drops globallycoherent qualifier when used in a struct
#ifndef RWCoherentByteAddressBufferRef
#define RWCoherentByteAddressBufferRef RWByteAddressBuffer
#endif
// Flag to say if the compiler needs globallycoherent locals of RWCoherentByteAddressBufferRef/etc
#ifndef COMPILER_NEEDS_GLOBALLYCOHERENT_LOCALS
#define COMPILER_NEEDS_GLOBALLYCOHERENT_LOCALS 0
#endif
#ifndef ISOLATE
#define ISOLATE
#endif
#ifndef HOIST_DESCRIPTORS
#define HOIST_DESCRIPTORS
#endif
#ifndef CALL_SITE_DEBUGLOC
#define CALL_SITE_DEBUGLOC
#endif
#ifndef SCHEDULER_MIN_PRESSURE
#define SCHEDULER_MIN_PRESSURE
#endif
#ifndef MAX_OCCUPANCY
#define MAX_OCCUPANCY
#endif
#ifndef DISABLE_TARGET_OCCUPANCY_WARNING
#define DISABLE_TARGET_OCCUPANCY_WARNING
#endif
#ifndef DISABLE_POTENTIALLY_UNINITIALIZED_WARNING
#define DISABLE_POTENTIALLY_UNINITIALIZED_WARNING
#endif
#ifndef ALLOW_NO_PS_EXPORT
#define ALLOW_NO_PS_EXPORT
#endif
#ifndef ADAPTIVE_LICM
#define ADAPTIVE_LICM
#endif
// ---------------------------------------------------- Interpolator attribute fallbacks
#ifndef COMPRESSED_16_FLOAT
#define COMPRESSED_16_FLOAT
#endif
#ifndef COMPRESSED_16_UNORM
#define COMPRESSED_16_UNORM
#endif
#ifndef COMPRESSED_16_SNORM
#define COMPRESSED_16_SNORM
#endif
#ifndef COMPRESSED_16_UINT
#define COMPRESSED_16_UINT
#endif
#ifndef COMPRESSED_16_INT
#define COMPRESSED_16_INT
#endif
#ifndef COMPRESSED_8_UNORM
#define COMPRESSED_8_UNORM
#endif
#ifndef COMPRESSED_8_SNORM
#define COMPRESSED_8_SNORM
#endif
#ifndef COMPRESSED_8_UINT
#define COMPRESSED_8_UINT
#endif
#ifndef CUSTOM_INTERPOLATION
#define CUSTOM_INTERPOLATION nointerpolation
#endif
// ---------------------------------------------------- Global uses
#define USE_DEVELOPMENT_SHADERS (COMPILE_SHADERS_FOR_DEVELOPMENT && PLATFORM_SUPPORTS_DEVELOPMENT_SHADERS)
// ---------------------------------------------------- Indirect parameter support
// sizeof(FRHIDispatchIndirectParametersNoPadding) / sizeof(uint)
#define DISPATCH_INDIRECT_NO_PADDING_UINT_COUNT 3
// sizeof(FRHIDispatchIndirectParameters) / sizeof(uint)
// The size of FRHIDispatchIndirectParameters may vary per-platform due to padding requirements. Platforms which diverge
// from the default of 3 uints must define DISPATCH_INDIRECT_UINT_COUNT in their PlatformCommon.ush to override the default
// behavior implemented here.
#ifndef DISPATCH_INDIRECT_UINT_COUNT
#define DISPATCH_INDIRECT_UINT_COUNT DISPATCH_INDIRECT_NO_PADDING_UINT_COUNT
void WriteDispatchIndirectArgs(RWBuffer<uint> RWIndirectDispatchArgsBuffer, in uint InIndex, in uint InIndirectArgX, in uint InIndirectArgY, in uint InIndirectArgZ)
{
RWIndirectDispatchArgsBuffer[DISPATCH_INDIRECT_UINT_COUNT * InIndex + 0] = InIndirectArgX;
RWIndirectDispatchArgsBuffer[DISPATCH_INDIRECT_UINT_COUNT * InIndex + 1] = InIndirectArgY;
RWIndirectDispatchArgsBuffer[DISPATCH_INDIRECT_UINT_COUNT * InIndex + 2] = InIndirectArgZ;
}
#endif // #ifndef DISPATCH_INDIRECT_UINT_COUNT
void WriteDispatchIndirectArgs(RWBuffer<uint> RWIndirectDispatchArgsBuffer, in uint InIndex, in uint3 InIndirectArg)
{
WriteDispatchIndirectArgs(RWIndirectDispatchArgsBuffer, InIndex, InIndirectArg.x, InIndirectArg.y, InIndirectArg.z);
}
// sizeof(FRHIDrawIndirectParameters) / sizeof(uint)
#define DRAW_INDIRECT_UINT_COUNT 4
// sizeof(FRHIDrawIndexedIndirectParameters) / sizeof(uint)
#define DRAW_INDEXED_INDIRECT_UINT_COUNT 5
// ---------------------------------------------------- Compiler missing implementations
#if COMPILER_NEEDS_DETERMINANT
float determinant(float3x3 M)
{
return
M[0][0] * (M[1][1] * M[2][2] - M[1][2] * M[2][1]) -
M[1][0] * (M[0][1] * M[2][2] - M[0][2] * M[2][1]) +
M[2][0] * (M[0][1] * M[1][2] - M[0][2] * M[1][1]);
}
#endif
#if COMPILER_HLSLCC
#define log10(x) log((x)) / log(10.0)
#endif
#if !COMPILER_SUPPORTS_MINMAX3
float min3(float a, float b, float c)
{
return min(a, min(b, c));
}
int min3(int a, int b, int c)
{
return min(a, min(b, c));
}
uint min3(uint a, uint b, uint c)
{
return min(a, min(b, c));
}
DECLARE_VECTOR_FUNCTION_OVERLOAD_3_PARAM(min3, float)
DECLARE_VECTOR_FUNCTION_OVERLOAD_3_PARAM(min3, int)
DECLARE_VECTOR_FUNCTION_OVERLOAD_3_PARAM(min3, uint)
float max3(float a, float b, float c)
{
return max(a, max(b, c));
}
int max3(int a, int b, int c)
{
return max(a, max(b, c));
}
uint max3(uint a, uint b, uint c)
{
return max(a, max(b, c));
}
DECLARE_VECTOR_FUNCTION_OVERLOAD_3_PARAM(max3, float)
DECLARE_VECTOR_FUNCTION_OVERLOAD_3_PARAM(max3, int)
DECLARE_VECTOR_FUNCTION_OVERLOAD_3_PARAM(max3, uint)
#if PLATFORM_SUPPORTS_REAL_TYPES
half min3(half a, half b, half c)
{
return min(a, min(b, c));
}
int16_t min3(int16_t a, int16_t b, int16_t c)
{
return min(a, min(b, c));
}
uint16_t min3(uint16_t a, uint16_t b, uint16_t c)
{
return min(a, min(b, c));
}
DECLARE_VECTOR_FUNCTION_OVERLOAD_3_PARAM(min3, half)
DECLARE_VECTOR_FUNCTION_OVERLOAD_3_PARAM(min3, int16_t)
DECLARE_VECTOR_FUNCTION_OVERLOAD_3_PARAM(min3, uint16_t)
half max3(half a, half b, half c)
{
return max(a, max(b, c));
}
int16_t max3(int16_t a, int16_t b, int16_t c)
{
return max(a, max(b, c));
}
uint16_t max3(uint16_t a, uint16_t b, uint16_t c)
{
return max(a, max(b, c));
}
DECLARE_VECTOR_FUNCTION_OVERLOAD_3_PARAM(max3, half)
DECLARE_VECTOR_FUNCTION_OVERLOAD_3_PARAM(max3, int16_t)
DECLARE_VECTOR_FUNCTION_OVERLOAD_3_PARAM(max3, uint16_t)
#endif // PLATFORM_SUPPORTS_REAL_TYPES
#endif // !COMPILER_SUPPORTS_MINMAX3
// https://devblogs.microsoft.com/directx/announcing-hlsl-2021/
// HLSL 2021 supports Logical Operator Short Circuiting. To do vector bool operations, need to use and() or() select()
// Sadly the HLSL2021 standard does not overload select() very well...
#define select(cond,a,b) select_internal(cond,a,b)
#define DEFINE_SELECT(TYPE) \
TYPE select_internal(bool c, TYPE a, TYPE b) { return TYPE (c ? a.x : b.x); } \
\
TYPE##2 select_internal(bool c, TYPE a, TYPE##2 b) { return TYPE##2(c ? a : b.x, c ? a : b.y); } \
TYPE##2 select_internal(bool c, TYPE##2 a, TYPE b) { return TYPE##2(c ? a.x : b , c ? a.y : b ); } \
TYPE##2 select_internal(bool c, TYPE##2 a, TYPE##2 b) { return TYPE##2(c ? a.x : b.x, c ? a.y : b.y); } \
TYPE##2 select_internal(bool2 c, TYPE a, TYPE b) { return TYPE##2(c.x ? a : b , c.y ? a : b ); } \
TYPE##2 select_internal(bool2 c, TYPE a, TYPE##2 b) { return TYPE##2(c.x ? a : b.x, c.y ? a : b.y); } \
TYPE##2 select_internal(bool2 c, TYPE##2 a, TYPE b) { return TYPE##2(c.x ? a.x : b , c.y ? a.y : b ); } \
TYPE##2 select_internal(bool2 c, TYPE##2 a, TYPE##2 b) { return TYPE##2(c.x ? a.x : b.x, c.y ? a.y : b.y); } \
\
TYPE##3 select_internal(bool c, TYPE a, TYPE##3 b) { return TYPE##3(c ? a : b.x, c ? a : b.y, c ? a : b.z); } \
TYPE##3 select_internal(bool c, TYPE##3 a, TYPE b) { return TYPE##3(c ? a.x : b , c ? a.y : b , c ? a.z : b ); } \
TYPE##3 select_internal(bool c, TYPE##3 a, TYPE##3 b) { return TYPE##3(c ? a.x : b.x, c ? a.y : b.y, c ? a.z : b.z); } \
TYPE##3 select_internal(bool3 c, TYPE a, TYPE b) { return TYPE##3(c.x ? a : b , c.y ? a : b , c.z ? a : b ); } \
TYPE##3 select_internal(bool3 c, TYPE a, TYPE##3 b) { return TYPE##3(c.x ? a : b.x, c.y ? a : b.y, c.z ? a : b.z); } \
TYPE##3 select_internal(bool3 c, TYPE##3 a, TYPE b) { return TYPE##3(c.x ? a.x : b , c.y ? a.y : b , c.z ? a.z : b ); } \
TYPE##3 select_internal(bool3 c, TYPE##3 a, TYPE##3 b) { return TYPE##3(c.x ? a.x : b.x, c.y ? a.y : b.y, c.z ? a.z : b.z); } \
\
TYPE##4 select_internal(bool c, TYPE a, TYPE##4 b) { return TYPE##4(c ? a : b.x, c ? a : b.y, c ? a : b.z, c ? a : b.w); } \
TYPE##4 select_internal(bool c, TYPE##4 a, TYPE b) { return TYPE##4(c ? a.x : b , c ? a.y : b , c ? a.z : b , c ? a.w : b ); } \
TYPE##4 select_internal(bool c, TYPE##4 a, TYPE##4 b) { return TYPE##4(c ? a.x : b.x, c ? a.y : b.y, c ? a.z : b.z, c ? a.w : b.w); } \
TYPE##4 select_internal(bool4 c, TYPE a, TYPE b) { return TYPE##4(c.x ? a : b , c.y ? a : b , c.z ? a : b , c.w ? a : b ); } \
TYPE##4 select_internal(bool4 c, TYPE a, TYPE##4 b) { return TYPE##4(c.x ? a : b.x, c.y ? a : b.y, c.z ? a : b.z, c.w ? a : b.w); } \
TYPE##4 select_internal(bool4 c, TYPE##4 a, TYPE b) { return TYPE##4(c.x ? a.x : b , c.y ? a.y : b , c.z ? a.z : b , c.w ? a.w : b ); } \
TYPE##4 select_internal(bool4 c, TYPE##4 a, TYPE##4 b) { return TYPE##4(c.x ? a.x : b.x, c.y ? a.y : b.y, c.z ? a.z : b.z, c.w ? a.w : b.w); } \
DEFINE_SELECT(bool)
#if !(COMPILER_HLSL || COMPILER_DXC || COMPILER_HLSLCC) || PLATFORM_NEEDS_SELECT_UINT
// @todo-lh: Ambiguous for DXC and HLSLcc if no suffix is provided for integer literals
DEFINE_SELECT(uint)
#endif
DEFINE_SELECT(int)
DEFINE_SELECT(float)
#if PLATFORM_SUPPORTS_REAL_TYPES
DEFINE_SELECT(half)
#if !(COMPILER_HLSL || COMPILER_DXC || COMPILER_HLSLCC)
// @todo-lh: Ambiguous for DXC and HLSLcc if no suffix is provided for integer literals
DEFINE_SELECT(uint16_t)
#endif
DEFINE_SELECT(int16_t)
#endif
#undef DEFINE_SELECT
// Works around bug in the spirv for the missing implementation of the and() and or() intrinsics.
bool and_internal(bool a, bool b) { return bool(a && b); }
bool2 and_internal(bool2 a, bool2 b) { return bool2(a.x && b.x, a.y && b.y); }
bool3 and_internal(bool3 a, bool3 b) { return bool3(a.x && b.x, a.y && b.y, a.z && b.z); }
bool4 and_internal(bool4 a, bool4 b) { return bool4(a.x && b.x, a.y && b.y, a.z && b.z, a.w && b.w); }
bool or_internal(bool a, bool b) { return bool(a || b); }
bool2 or_internal(bool2 a, bool2 b) { return bool2(a.x || b.x, a.y || b.y); }
bool3 or_internal(bool3 a, bool3 b) { return bool3(a.x || b.x, a.y || b.y, a.z || b.z); }
bool4 or_internal(bool4 a, bool4 b) { return bool4(a.x || b.x, a.y || b.y, a.z || b.z, a.w || b.w); }
#define and(a, b) and_internal(a, b)
#define or(a, b) or_internal(a, b)
#if PLATFORM_SUPPORTS_REAL_TYPES && !defined(COMPILER_SUPPORTS_PACK_B32_B16)
// Function that explicitly use RDNA's v_pack_b32_f16 on supported platform. Note that RDNA's documentation call this instruction v_pack_b32_f16
// but really is a v_pack_b32_b16.
half2 v_pack_b32_b16(half a, half b)
{
return half2(a, b);
}
int16_t2 v_pack_b32_b16(int16_t a, int16_t b)
{
return int16_t2(a, b);
}
uint16_t2 v_pack_b32_b16(uint16_t a, uint16_t b)
{
return uint16_t2(a, b);
}
#endif
#if !defined(COMPILER_SUPPORTS_COND_MASK)
float CondMask(bool Cond, float Src0, float Src1) { return Cond ? Src0 : Src1; }
float2 CondMask(bool Cond, float2 Src0, float2 Src1) { return Cond ? Src0 : Src1; }
float3 CondMask(bool Cond, float3 Src0, float3 Src1) { return Cond ? Src0 : Src1; }
float4 CondMask(bool Cond, float4 Src0, float4 Src1) { return Cond ? Src0 : Src1; }
int CondMask(bool Cond, int Src0, int Src1) { return Cond ? Src0 : Src1; }
int2 CondMask(bool Cond, int2 Src0, int2 Src1) { return Cond ? Src0 : Src1; }
int3 CondMask(bool Cond, int3 Src0, int3 Src1) { return Cond ? Src0 : Src1; }
int4 CondMask(bool Cond, int4 Src0, int4 Src1) { return Cond ? Src0 : Src1; }
uint CondMask(bool Cond, uint Src0, uint Src1) { return Cond ? Src0 : Src1; }
uint2 CondMask(bool Cond, uint2 Src0, uint2 Src1) { return Cond ? Src0 : Src1; }
uint3 CondMask(bool Cond, uint3 Src0, uint3 Src1) { return Cond ? Src0 : Src1; }
uint4 CondMask(bool Cond, uint4 Src0, uint4 Src1) { return Cond ? Src0 : Src1; }
#endif
#if !defined(COMPILER_SUPPORTS_UNPACKBYTEN)
float UnpackByte0(uint v) { return float(v & 0xff); }
float UnpackByte1(uint v) { return float((v >> 8) & 0xff); }
float UnpackByte2(uint v) { return float((v >> 16) & 0xff); }
float UnpackByte3(uint v) { return float(v >> 24); }
#endif // !COMPILER_SUPPORTS_UNPACKBYTEN
#if !defined(COMPILER_SUPPORTS_BITFIELD_INTRINSICS)
#define COMPILER_SUPPORTS_BITFIELD_INTRINSICS 0
// Software emulation using SM5/GCN semantics.
// Fast as long as shifts, sizes and offsets are compile-time constant.
// TODO: Should we consider weaker semantics to allow for a more efficient implementation in the dynamic case?
uint BitFieldInsertU32(uint Mask, uint Preserve, uint Enable)
{
return (Preserve & Mask) | (Enable & ~Mask);
}
uint BitFieldExtractU32(uint Data, uint Size, uint Offset)
{
// Shift amounts are implicitly &31 in HLSL, so they should be optimized away on most platforms
// In GLSL shift amounts < 0 or >= word_size are undefined, so we better be explicit
Size &= 31;
Offset &= 31;
return (Data >> Offset) & ((1u << Size) - 1u);
}
int BitFieldExtractI32(int Data, uint Size, uint Offset)
{
Size &= 31u;
Offset &= 31u;
const uint Shift = (32u - Size) & 31u;
const int Value = (Data >> Offset) & int((1u << Size) - 1u);
return (Value << Shift) >> Shift;
}
uint BitFieldMaskU32(uint MaskWidth, uint MaskLocation)
{
MaskWidth &= 31u;
MaskLocation &= 31u;
return ((1u << MaskWidth) - 1u) << MaskLocation;
}
#endif
#if !defined(COMPILER_SUPPORTS_24BIT_INTRINSICS)
#define COMPILER_SUPPORTS_24BIT_INTRINSICS 0
int MulI24(int I1, int I2)
{
// D.i32 = S0.i24 * S1.i24
return (I1 * I2);
}
uint MulU24(uint U1, uint U2)
{
// D.u32 = S0.u24 * S1.u24
return U1 * U2;
}
int MadI24(int I1, int I2, int I3)
{
// D.i = S0.i[23:0] * S1.i[23:0] + S2.i
return I1 * I2 + I3;
}
uint MadU24(uint U1, uint U2, uint U3)
{
// D.u = S0.u[23:0] * S1.u[23:0] + S2.u
return U1 * U2 + U3;
}
#endif
uint Padding(uint Value, uint Pow2)
{
return (Value + Pow2 - 1u) & ~(Pow2 - 1u);
}
uint CeilLog2(uint Value)
{
return Value < 2u ? 0u : firstbithigh(Value - 1u) + 1u;
}
float BitFieldExtractFloat(uint Bits, uint Count, uint Offset)
{
return BitFieldExtractU32(Bits, Count, Offset) / (float)BitFieldMaskU32(Count, 0u);
}
#if !defined(COMPILER_SUPPORTS_BITALIGN)
#define COMPILER_SUPPORTS_BITALIGN 0
uint BitAlignU32(uint High, uint Low, uint Shift)
{
Shift &= 31u;
uint Result = Low >> Shift;
Result |= Shift > 0u ? (High << (32u - Shift)) : 0u;
return Result;
}
#endif
#ifndef COMPILER_SUPPORTS_BYTEALIGN
#define COMPILER_SUPPORTS_BYTEALIGN 0
uint ByteAlignU32(uint High, uint Low, uint Shift)
{
return BitAlignU32(High, Low, Shift * 8);
}
#endif // #ifndef COMPILER_SUPPORTS_BYTEALIGN
#if COMPILER_HLSLCC
#define ddx_fine(x) ddx(x)
#define ddy_fine(y) ddy(y)
#endif
#ifndef COMPILER_SUPPORTS_ULONG_TYPES
#define UlongType uint2
UlongType PackUlongType(uint2 Value)
{
return Value;
}
uint2 UnpackUlongType(UlongType Value)
{
return Value;
}
#endif
// Prefix sum of Bits masked to the bits lower than Index.
uint MaskedBitCount( uint2 Bits, uint Index )
{
bool bLow = Index < 32;
uint Mask = 1u << ( Index - ( bLow ? 0 : 32 ) );
Mask -= 1;
uint Offset;
Offset = countbits( Bits.x & ( bLow ? Mask : ~0u ) );
Offset += countbits( Bits.y & ( bLow ? 0 : Mask ) );
return Offset;
}
// Lock a critical region of code within a pixel shader and guarantees no concurrent execution for the same pixel
#ifndef RASTER_ORDERED_VIEW_LOCK
#define RASTER_ORDERED_VIEW_LOCK()
#endif
// Unlock a critical region of code within a pixel shader.
#ifndef RASTER_ORDERED_VIEW_UNLOCK
#define RASTER_ORDERED_VIEW_UNLOCK()
#endif
#if PLATFORM_SUPPORTS_SM6_0_WAVE_OPERATIONS
#ifndef COMPILER_SUPPORTS_TO_SCALAR_MEMORY
#define COMPILER_SUPPORTS_TO_SCALAR_MEMORY 1
#define ToScalarMemory(x) WaveReadLaneFirst(x)
#endif
#ifndef COMPILER_SUPPORTS_MASKED_BIT_COUNT
#define COMPILER_SUPPORTS_MASKED_BIT_COUNT 1
uint MaskedBitCount( uint2 Bits )
{
return MaskedBitCount( Bits, WaveGetLaneIndex() );
}
#endif
#if COMPILER_DXC
uint2 WaveBallot( bool Expr )
{
return WaveActiveBallot( Expr ).xy;
}
#endif
#ifndef WaveReadLaneLast
uint WaveGetActiveLaneIndexLast()
{
uint2 ActiveMask = WaveActiveBallot( true ).xy;
return firstbithigh( ActiveMask.y ? ActiveMask.y : ActiveMask.x ) + ( ActiveMask.y ? 32 : 0 );
}
#define WaveReadLaneLast(x) WaveReadLaneAt( x, WaveGetActiveLaneIndexLast() )
#endif
#endif // PLATFORM_SUPPORTS_SM6_0_WAVE_OPERATIONS
#if !defined(COMPILER_SUPPORTS_WAVE_INCLUSIVE_PREFIX_SUM)
#define COMPILER_SUPPORTS_WAVE_INCLUSIVE_PREFIX_SUM 0
#define WaveInclusivePrefixSum(x) (WavePrefixSum(x) + x)
#endif
// Give hint to compiler to move one value to scalar unit.
#if !defined(ToScalarMemory) && !defined(COMPILER_SUPPORTS_TO_SCALAR_MEMORY)
#define ToScalarMemory(x) (x)
#endif
#if FEATURE_LEVEL < FEATURE_LEVEL_ES3_1 && !COMPILER_METAL
// DX11 (feature levels >= 10) feature sets natively supports uints in shaders; we just use floats on other platforms.
#define uint4 int4
#endif
#ifndef SNORM
#if COMPILER_HLSLCC
#define SNORM
#define UNORM
#else
#define SNORM snorm
#define UNORM unorm
#endif
#endif
#ifndef INFINITE_FLOAT
#if COMPILER_HLSLCC
#define INFINITE_FLOAT 3.402823e+38
#else
#define INFINITE_FLOAT 1.#INF
#endif
#endif
#ifndef RWTextureCube
#define RWTextureCube RWTexture2DArray
#endif
#ifndef PLATFORM_NEEDS_PRECISE_SHADOW_DEPTH
#define PLATFORM_NEEDS_PRECISE_SHADOW_DEPTH 0
#endif
// Little tools to help with packing scalars arrays
#ifndef CALC_SCALAR_ARRAY_SIZE
#define CALC_SCALAR_ARRAY_SIZE(ElementCount) ((ElementCount+3)/4)
#endif
#ifndef DECLARE_SCALAR_ARRAY
#define DECLARE_SCALAR_ARRAY(ScalarType, ScalarName, ElementCount) ScalarType##4 ScalarName[CALC_SCALAR_ARRAY_SIZE(ElementCount)]
#endif
#ifndef GET_SCALAR_ARRAY_ELEMENT
#define GET_SCALAR_ARRAY_ELEMENT(PackedArray, ElementIndex) PackedArray[(uint)ElementIndex>>2u][(uint)ElementIndex&3u]
#endif