// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= DiaphragmDOF/DOFGatherCommon.usf: common code shared by other gather USH files for DOFGatherPass.usf. =============================================================================*/ #pragma once #include "DOFCommon.ush" #include "DOFCocTileCommon.ush" //------------------------------------------------------- DEBUG COMPILE TIME CONFIG // To iterate faster on the gathering kernel, reduce the number of sample to minimum // to get the shader compiler building quicker regardless of the permutation. #define DEBUG_FORCE_LOW_RING_COUNT 0 #define DEBUG_NO_FAST_ACCUMULATOR 0 // When on, show FFastAccumulator in green, versus FGatherAccumulator in red. #define DEBUG_FAST_ACCUMULATOR 0 // Force to disable random offset of the gathering kernel #define DEBUG_NO_RANDOM_OFFSET 0 // Force to sample mip level that have same resolution as output. #define DEBUG_FORCE_GATHER_HIGHEST_MIP_LEVEL 0 //------------------------------------------------------- DIMENSIONS VALUES. // Matching C++'s FRCPassDiaphragmDOFGather::EQualityConfig #define GATHER_QUALITY_LOW_QUALITY 0 #define GATHER_QUALITY_HIGH_QUALITY 1 #define GATHER_QUALITY_SCATTER_OCCLUSION_OUTPUT 2 #define GATHER_QUALITY_CINEMATIC 3 //------------------------------------------------------- ENUM VALUES /** Different gathering accumulator implementation to be used. */ // In house: simple one bucket accumulator for slight out of focus and separate foreground hole filling. #define GATHER_ACCUMULATOR_METHOD_SIMPLE 0 // JIMENEZ SIGGRAPH 2014: CALL OF DUTY WAREFARE: 2 layers only, closest layer defined by tiled Coc. #define GATHER_ACCUMULATOR_METHOD_JIMENEZ2014 1 // In house: each sampling ring is a bin. #define GATHER_ACCUMULATOR_METHOD_RINGBINNING 2 /** Layouts of the kernel's samples to use. */ // Disk (or custom area if simulating a bokeh with a LUT) that scales with kernel radius. #define KERNEL_LAYOUT_SCALABLE_DISK 0 // Non scalable square shaped kernel that have all samples aligned with input samples. #define KERNEL_LAYOUT_ALIGNED_SQUARE 1 /** Kernel sampling density compile time mode. */ // The kernel sample density is constent #define KERNEL_DENSITY_CONSTANT 0 #define KERNEL_DENSITY_CONSTANT_HEXAWEB 1 // The kernel offer a run time toggable between: // - constant sample density; // - donut area with same density as if was a fully constant density, and a higher density disk in its center. #define KERNEL_DENSITY_HIGHER_IN_CENTER_DISK 2 // The kernel is hexagonal web, that have 1/4 sampling density everywhere but the last ring, particularily useful // for fast gathering on hardware that can particularily be texture fetch bound. #define KERNEL_DENSITY_LOWER_IN_CENTER_HEXAWEB 3 // Kernel that does multiple passes of entire disks at different mip levels. #define KERNEL_DENSITY_RECURSIVE_DISKS 4 // Kernel is constant, but with varying number of rings #define KERNEL_DENSITY_CONSTANT_DYNAMIC_RING_COUNT 5 /** Technic to use with mip level. */ // non conservative with interleaved offset. #define MIP_LEVEL_METHOD_INTERLEAVED_OFFSET 0 // 1: conservative. #define MIP_LEVEL_METHOD_CONSERVATIVE_NO_RANDOM 1 //------------------------------------------------------- COMPILE TIME CONFIG // Configures the layer processing. #if DIM_LAYER_PROCESSING == LAYER_PROCESSING_FOREGROUND_ONLY #define GATHER_ACCUMULATOR_METHOD (GATHER_ACCUMULATOR_METHOD_JIMENEZ2014) #define CONFIG_ENABLE_FAST_ACCUMULATOR 1 #elif DIM_LAYER_PROCESSING == LAYER_PROCESSING_FOREGROUND_HOLE_FILLING #define GATHER_ACCUMULATOR_METHOD (GATHER_ACCUMULATOR_METHOD_SIMPLE) #elif DIM_LAYER_PROCESSING == LAYER_PROCESSING_BACKGROUND_ONLY #define GATHER_ACCUMULATOR_METHOD (GATHER_ACCUMULATOR_METHOD_RINGBINNING) #define CONFIG_ENABLE_FAST_ACCUMULATOR 1 // Mirror the bokeh. #define CONFIG_POINT_MIRROR_BOKEH -1 // Background DOF can suffer under sampling on smaller out of focus, because // the gathering kernel is too large. #define CONFIG_KERNEL_SAMPLING_DENSITY_DRIVER 1 // Background need coc radius error correction to reduce amount of background leaking. #define CONFIG_COC_RADIUS_CORRECTION 1 #elif DIM_LAYER_PROCESSING == LAYER_PROCESSING_SLIGHT_OUT_OF_FOCUS #define GATHER_ACCUMULATOR_METHOD (GATHER_ACCUMULATOR_METHOD_SIMPLE) // Slight out of focus just gather all samples. #define CONFIG_KERNEL_LAYOUT (KERNEL_LAYOUT_ALIGNED_SQUARE) #else #error Unknown layer processing. #endif // Configures the quality settings. #if DIM_GATHER_QUALITY == GATHER_QUALITY_LOW_QUALITY #define CONFIG_ACCUMULATOR_FULL_ALU 0 #define CONFIG_FAST_ACCUMULATOR_RING_COUNT ((DIM_GATHER_RING_COUNT) - 1) #define CONFIG_FAST_ACCUMULATOR_KERNEL_DENSITY (KERNEL_DENSITY_CONSTANT_HEXAWEB) //#define CONFIG_FAST_ACCUMULATOR_KERNEL_DENSITY (KERNEL_DENSITY_HEXAWEB_LOWER_IN_CENTER) // Highlights needs a bit of help. #define CONFIG_SLIGHT_RING_ROTATION 1 #elif DIM_GATHER_QUALITY == GATHER_QUALITY_HIGH_QUALITY #define CONFIG_WEIGHT_SAMPLE_FROM_COC 1 #define CONFIG_MIRRORED_SAMPLER 1 #define CONFIG_PETZVAL 1 #elif DIM_GATHER_QUALITY == GATHER_QUALITY_SCATTER_OCCLUSION_OUTPUT #define CONFIG_WEIGHT_SAMPLE_FROM_COC 1 #define CONFIG_GENERATE_SCATTER_OCCLUSION_BUFFER 1 #define CONFIG_MIRRORED_SAMPLER 1 #define CONFIG_PETZVAL 1 #elif DIM_GATHER_QUALITY == GATHER_QUALITY_CINEMATIC #define CONFIG_WEIGHT_SAMPLE_FROM_COC 1 #define CONFIG_GENERATE_SCATTER_OCCLUSION_BUFFER 1 #define CONFIG_MIRRORED_SAMPLER 1 #define CONFIG_LAYER_GATHERING 1 #define CONFIG_PETZVAL 1 #else #error Unknon gathering quality. #endif // Configures the layout accepted has input. #if CONFIG_DOF_ALPHA #define CONFIG_GATHER_INPUT_LAYOUT (GATHER_INPUT_LAYOUT_RGB_ALPHA_COC) #elif DIM_RGB_COLOR_BUFFER #define CONFIG_GATHER_INPUT_LAYOUT (GATHER_INPUT_LAYOUT_RGB_SEPARATE_COC) #else #define CONFIG_GATHER_INPUT_LAYOUT (GATHER_INPUT_LAYOUT_RGB_COC) #endif //------------------------------------------------------- DEFAULT CONFIG // Allows to branch at run time to use the fast accumulator to reduce VALU when coc // range in neighborhood is know to be small. #ifndef CONFIG_ENABLE_FAST_ACCUMULATOR #define CONFIG_ENABLE_FAST_ACCUMULATOR 0 #endif // Defines the kernel density to use for the fast accumulator. #ifndef CONFIG_FAST_ACCUMULATOR_KERNEL_DENSITY #define CONFIG_FAST_ACCUMULATOR_KERNEL_DENSITY (KERNEL_DENSITY_CONSTANT) #endif // Defines the number of ring for fast accumulator. // It is good to lower this on texture fetch bound hardware, so that the texture fetch budget can be // fore accumulator that requires more sample because of the point sampling used. #ifndef CONFIG_FAST_ACCUMULATOR_RING_COUNT #define CONFIG_FAST_ACCUMULATOR_RING_COUNT (DIM_GATHER_RING_COUNT) #endif // Selects the code to drive the kernel sampling density. #ifndef CONFIG_KERNEL_SAMPLING_DENSITY_DRIVER #define CONFIG_KERNEL_SAMPLING_DENSITY_DRIVER 0 #endif // Technic to use with mip level. #ifndef CONFIG_MIP_LEVEL_METHOD #define CONFIG_MIP_LEVEL_METHOD (MIP_LEVEL_METHOD_INTERLEAVED_OFFSET) #endif // Kernel sample layout to use for gathering. #ifndef CONFIG_KERNEL_LAYOUT #define CONFIG_KERNEL_LAYOUT (KERNEL_LAYOUT_SCALABLE_DISK) #endif // Give hint to the compiler about what can be scalarized. #define CONFIG_SGPR_HINTS 1 // Clamp the input buffers' UV to avoid sampling outside viewport. #define CONFIG_CLAMP_INPUT_BUFFER_UV 1 // Whether the samples should be weighted according to their Coc. #ifndef CONFIG_GENERATE_SCATTER_OCCLUSION_BUFFER #define CONFIG_GENERATE_SCATTER_OCCLUSION_BUFFER 0 #endif // Whether the samples should be weighted according to their Coc. #ifndef CONFIG_WEIGHT_SAMPLE_FROM_COC #define CONFIG_WEIGHT_SAMPLE_FROM_COC 0 #endif // Whether to allow accumulator do its highest ALU computation. #ifndef CONFIG_ACCUMULATOR_FULL_ALU #define CONFIG_ACCUMULATOR_FULL_ALU 1 #endif // Whether to point mirror the bokeh. #ifndef CONFIG_POINT_MIRROR_BOKEH #define CONFIG_POINT_MIRROR_BOKEH 1 #endif // Uses mirrored sampler when gathering outside viewport rect. #ifndef CONFIG_MIRRORED_SAMPLER #define CONFIG_MIRRORED_SAMPLER 0 #endif // Substract the CocRadius error to the sample distance to fight against layering opacity issues caused by undersampling. #ifndef CONFIG_COC_RADIUS_CORRECTION #define CONFIG_COC_RADIUS_CORRECTION 0 #endif /** Defines the maximum number of gathering sampling density changes supported in the kernel. */ #ifndef CONFIG_MAX_SAMPLING_DENSITY_CHANGES #define CONFIG_MAX_SAMPLING_DENSITY_CHANGES 3 #endif /** Adds a slight rotation to the samples to reduce interferance sample location and texel grid with the point sampler, * that improves highlight post filtering. */ #ifndef CONFIG_SLIGHT_RING_ROTATION #define CONFIG_SLIGHT_RING_ROTATION 0 #endif /** Whether the gathering is done in multiple layer over the kernel. */ #ifndef CONFIG_LAYER_GATHERING #define CONFIG_LAYER_GATHERING 0 #endif //------------------------------------------------------- CONFIG CHECKS #ifndef GATHER_ACCUMULATOR_METHOD #error You at the very least need to choose the an accumulator. #endif #ifndef CONFIG_GATHER_INPUT_LAYOUT #error You at the very least need to choose the gather input layout. #endif //------------------------------------------------------- CONFIG DERIVED VALUES // Wether the group size is larger than COC tile size. #define GROUP_SIZE_IS_LARGER_THAN_COC_TILE_SIZE 0 //------------------------------------------------------- STAND ALONE FUNCTIONS // Compute sample weight according's to its Coc radius. float ComputeSampleWeight(float CocRadius) { #if CONFIG_WEIGHT_SAMPLE_FROM_COC const float PixelRadius = 0.25; // = 0.5 / CocDownresSample; return min(rcp(PI * CocRadius * CocRadius), rcp(PI * PixelRadius * PixelRadius)); #else return 1.0; #endif } //------------------------------------------------------- STRUCTS /** Gather input generally from larger gathering radius. */ struct FLargerConvolution { /** Gathered color. */ float4 Color; /** Weight of the color. */ float Weight; /** Coc average and squared average. */ float2 CocAvgAndSquareAvg; }; /** Gathering parameters. */ struct FGatherInputParameters { // Compile time maximum number of rings to gather. uint MaxRingCount; // Runtime number of rings to gather <= MaxRingCount. uint RingCount; // buffer UV coordinate of the center of the kernel to gather. float2 InputBufferCenterUV; float2 ViewportUV; // Multiplication factors to map DispatchThreadID -> InputBufferUV. float2 DispatchThreadIdToInputBufferUV; // Radius of the kernel at half res pixels. float KernelRadius; // Random signals float Random[2]; // Whether going to use accumulator or fast accumulator. bool bFastGathering; // The Coc radius that is the closest to the camera. float ClosestCocRadius; // Saturated affine transformation. float2 ConsiderCocRadiusAffineTransformation0; float2 ConsiderCocRadiusAffineTransformation1; float2 ConsiderAbsCocRadiusAffineTransformation; // TODO: clean that with CocRadiusMinMaxBoundaries float MaxRecombineAbsCocRadius; // Sampling density compile time mode. KERNEL_DENSITY_* uint KernelSamplingDensityMode; // Compile time number of rings for density changes. uint DensityChangeRingCount; // Compile time max number of density changes allowed. uint MaxDensityChangeCount; // Tile constant about what is the smallest intersectable radius. float MinIntersectableCocRadiusAbs; }; /** Informations about a ring. */ struct FGatherRingInfos { /** Id of the ring. 0 is the smallest ring after the center sample. */ uint RingId; /** Total number of samples on the ring. */ uint SampleCount; /** Compile time constant on whether this is the first accumualted ring. */ bool bIsFirstRing; // Total weight of the ring. float Weight; /** Radius of the ring in pixels from the center of the kernel. */ float Radius; }; /** Informations about the kernel when the accumulator resolves. */ struct FGatherResolveInfos { // Number of accumulated samples. // This is a float because of density changes that can happen with AmendAccumulatedRingsWeight(). float SamplesCount; }; /** Structs that holds data about a sample for gathering. */ struct FGatherSample { // Sample's scene color (and optionally alpha channel). float4 Color; // Sample's radius of the Coc float CocRadius; // Sample distance from center of kernel, in CocRadius unit. float Distance; // Sample's intersection. float Intersection; }; /** Gathering accumulator output. */ struct FAccumulatorOutput { // Foreground color. float4 ForegroundColor; // Foreground alpha channel to use to compose on in focus and background. float ForegroundAlpha; // Foreground hole filling color and alpha. float4 ForegroundHoleFillingColor; float ForegroundHoleFillingAlpha; // Background color. float4 BackgroundColor; // Weight of the backrgound. float BackgroundWeight; // Coc average and variance for background. float2 BackgroundCocAvgAndSquareAvg; // Slight out of focus color and opacity. float4 SlightFocusColor; float SlightFocusOpacity; }; //------------------------------------------------------- METHODS // Returns whether this Coc radius is considered or not for this pass. If not considered, it means this Coc radius will // be gathered at higher or lower resolution gathering pass. float IsConsideredCocRadius(in const FGatherInputParameters GatherParameters, float SampleCocRadius) { // Hint: This might look expensive, but this is just for framework flexibility: most of the // AffineTransformation are actually set so that SaturateWithAffineTransformation always returns // 1 at compile time. return ( SaturateWithAffineTransformation(SampleCocRadius, GatherParameters.ConsiderCocRadiusAffineTransformation0) * SaturateWithAffineTransformation(SampleCocRadius, GatherParameters.ConsiderCocRadiusAffineTransformation1) * SaturateWithAffineTransformation(abs(SampleCocRadius), GatherParameters.ConsiderAbsCocRadiusAffineTransformation)); } FAccumulatorOutput CreateAccumulatorOutput() { FAccumulatorOutput AccumulatorOutput; AccumulatorOutput.ForegroundColor = 0; AccumulatorOutput.ForegroundAlpha = 0; AccumulatorOutput.ForegroundHoleFillingColor = 0; AccumulatorOutput.ForegroundHoleFillingAlpha = 1; AccumulatorOutput.BackgroundColor = 0; AccumulatorOutput.BackgroundWeight = 0; AccumulatorOutput.BackgroundCocAvgAndSquareAvg = 0; AccumulatorOutput.SlightFocusColor = 0; AccumulatorOutput.SlightFocusOpacity = 0; return AccumulatorOutput; }