Files
UnrealEngine/Engine/Shaders/Private/ScreenSpaceDenoise/SSDSignalBufferEncoding.ush
2025-05-18 13:04:45 +08:00

850 lines
28 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "SSDSignalCore.ush"
#include "SSDPublicBufferEncoding.ush"
#include "../Lumen/LumenBufferEncoding.ush"
/** Whether the color should be clamped when encoding signal. */
#define CONFIG_ENCODING_CLAMP_COLOR 1
/** Selects the type that should be used when sampling a buffer */
#ifndef CONFIG_SIGNAL_INPUT_TEXTURE_TYPE
#define CONFIG_SIGNAL_INPUT_TEXTURE_TYPE SIGNAL_TEXTURE_TYPE_FLOAT4
#endif
/** Selects the type that should be used when sampling a buffer */
#ifndef CONFIG_SIGNAL_OUTPUT_TEXTURE_TYPE
#define CONFIG_SIGNAL_OUTPUT_TEXTURE_TYPE SIGNAL_TEXTURE_TYPE_FLOAT4
#endif
#if CONFIG_SIGNAL_INPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_FLOAT4
#define FSSDRawSample float4
#define FSSDTexture2D Texture2D
#elif CONFIG_SIGNAL_INPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT1 || CONFIG_SIGNAL_INPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT2 || CONFIG_SIGNAL_INPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT3 || CONFIG_SIGNAL_INPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT4
#if CONFIG_SIGNAL_INPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT1
#define FSSDRawSample uint
#elif CONFIG_SIGNAL_INPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT2
#define FSSDRawSample uint2
#elif CONFIG_SIGNAL_INPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT3
#define FSSDRawSample uint3
#elif CONFIG_SIGNAL_INPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT4
#define FSSDRawSample uint4
#else
#error Unknown input type for a signal texture.
#endif
#define FSSDTexture2D Texture2D<FSSDRawSample>
#else
#error Unknown input type for a signal texture.
#endif
#if CONFIG_SIGNAL_OUTPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_FLOAT4
#define FSSDOutputRawSample float4
#elif CONFIG_SIGNAL_OUTPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT1
#define FSSDOutputRawSample uint
#elif CONFIG_SIGNAL_OUTPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT2
#define FSSDOutputRawSample uint2
#elif CONFIG_SIGNAL_OUTPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT3
#define FSSDOutputRawSample uint3
#elif CONFIG_SIGNAL_OUTPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT4
#define FSSDOutputRawSample uint4
#else
#error Unknown output type for a signal texture.
#endif
#define FSSDRWTexture2D RWTexture2D<FSSDOutputRawSample>
float3 ClampColorForEncoding(float3 Color)
{
#if CONFIG_ENCODING_CLAMP_COLOR
Color = min(Color, MaxHalfFloat);
#endif
return Color;
}
float4 ClampColorForEncoding(float4 Color)
{
return float4(ClampColorForEncoding(Color.rgb), Color.a);
}
/** Raw data layout when sampling input texture of the denoiser. */
struct FSSDCompressedMultiplexedSample
{
FSSDRawSample VGPRArray[MAX_MULTIPLEXED_TEXTURES];
};
/** Decode input signal sample from raw float. */
void DecodeMultiplexedSignalsFromFloat4(
const uint SignalBufferLayout,
const uint MultiplexedSampleId,
const bool bNormalizeSample,
float4 RawSample[MAX_MULTIPLEXED_TEXTURES],
out FSSDSignalArray OutSamples,
out FSSDSignalFrequencyArray OutSampleFrequencies)
{
OutSamples = CreateSignalArrayFromScalarValue(0.0);
OutSampleFrequencies = CreateInvalidSignalFrequencyArray();
if (0)
{
}
#if 1
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_UNINITIALIZED)
{
// trash out the output sample to identify quickly a miss configured buffer layout.
OutSamples = CreateSignalArrayFromScalarValue(-INFINITE_FLOAT);
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_PENUMBRA_INPUT_NSPP)
{
UNROLL_N(MAX_SIGNAL_BATCH_SIZE)
for (uint BatchSignalId = 0; BatchSignalId < MAX_SIGNAL_BATCH_SIZE; BatchSignalId++)
{
uint MultiplexId = BatchSignalId;
// TODO(Denoiser): feed the actual number of sample.
OutSamples.Array[MultiplexId].SampleCount = (RawSample[MultiplexId].g == DENOISER_INVALID_HIT_DISTANCE ? 0.0 : 1.0);
OutSamples.Array[MultiplexId].MissCount = OutSamples.Array[MultiplexId].SampleCount * RawSample[MultiplexId].r;
OutSamples.Array[MultiplexId].TransmissionDistance = OutSamples.Array[MultiplexId].SampleCount * RawSample[MultiplexId].a;
OutSampleFrequencies.Array[MultiplexId].ClosestHitDistance = RawSample[MultiplexId].g;
FLATTEN
if (OutSamples.Array[MultiplexId].SampleCount == 0)
{
OutSampleFrequencies.Array[MultiplexId].ClosestHitDistance = DENOISER_INVALID_HIT_DISTANCE;
}
else if (OutSamples.Array[MultiplexId].MissCount > 0.999)
{
OutSampleFrequencies.Array[MultiplexId].ClosestHitDistance = DENOISER_MISS_HIT_DISTANCE;
}
}
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_PENUMBRA_HISTORY)
{
UNROLL_N(MAX_SIGNAL_BATCH_SIZE)
for (uint MultiplexId = 0; MultiplexId < MAX_SIGNAL_BATCH_SIZE; MultiplexId++)
{
float4 Channels = RawSample[MultiplexId].xyzw;
float SampleCount = bNormalizeSample ? (Channels.g > 0 ? 1 : 0) : (Channels.g);
OutSamples.Array[MultiplexId].MissCount = Channels.r * SampleCount;
OutSamples.Array[MultiplexId].SampleCount = SampleCount;
OutSamples.Array[MultiplexId].TransmissionDistance = Channels.a * SampleCount;
OutSampleFrequencies.Array[MultiplexId].WorldBluringRadius = Channels.b;
}
}
#endif
#if COMPILE_SIGNAL_COLOR_ARRAY >= 2 && SIGNAL_ARRAY_SIZE >= 2
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_POLYCHROMATIC_PENUMBRA_HARMONIC_INPUT)
{
// The RGS output same weigth for diffuse and specular given it depends only on shading model id.
float Weight = RawSample[0].a;
if (bNormalizeSample)
{
Weight = Weight > 0.0 ? 1.0 : 0.0;
}
// Decode diffuse
{
const uint MultiplexId = 0;
OutSamples.Array[MultiplexId].SampleCount = Weight;
OutSamples.Array[MultiplexId].ColorArray[0] = RawSample[0].rgb * Weight;
OutSamples.Array[MultiplexId].ColorArray[1] = RawSample[1].rgb * Weight;
}
// Decode specular
{
const uint MultiplexId = 1;
OutSamples.Array[MultiplexId].SampleCount = Weight;
OutSamples.Array[MultiplexId].ColorArray[0] = RawSample[2].rgb * Weight;
OutSamples.Array[MultiplexId].ColorArray[1] = RawSample[3].rgb * Weight;
}
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_POLYCHROMATIC_PENUMBRA_HARMONIC_RECONSTRUCTION)
{
// Decode diffuse
{
const uint MultiplexId = 0;
float Weight = RawSample[0].a;
if (bNormalizeSample)
{
Weight = Weight > 0.0 ? 1.0 : 0.0;
}
OutSamples.Array[MultiplexId].SampleCount = Weight;
OutSamples.Array[MultiplexId].ColorArray[0] = RawSample[0].rgb * Weight;
OutSamples.Array[MultiplexId].ColorArray[1] = RawSample[1].rgb * Weight;
}
// Decode specular
{
const uint MultiplexId = 1;
float Weight = RawSample[2].a;
if (bNormalizeSample)
{
Weight = Weight > 0.0 ? 1.0 : 0.0;
}
OutSamples.Array[MultiplexId].SampleCount = Weight;
OutSamples.Array[MultiplexId].ColorArray[0] = RawSample[2].rgb * Weight;
OutSamples.Array[MultiplexId].ColorArray[1] = RawSample[3].rgb * Weight;
}
}
#endif
#if COMPILE_SIGNAL_COLOR
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_POLYCHROMATIC_PENUMBRA_HISTORY)
{
// Decode diffuse harmonic
{
const uint MultiplexId = 0;
float Weight = RawSample[0].a;
if (bNormalizeSample)
{
Weight = Weight > 0 ? 1 : 0;
}
OutSamples.Array[MultiplexId].SampleCount = Weight;
OutSamples.Array[MultiplexId].SceneColor.rgb = RawSample[0].rgb * Weight;
}
#if SIGNAL_ARRAY_SIZE >= 2
// Decode specular harmonic
{
const uint MultiplexId = 1;
float Weight = RawSample[1].a;
if (bNormalizeSample)
{
Weight = Weight > 0 ? 1 : 0;
}
OutSamples.Array[MultiplexId].SampleCount = Weight;
OutSamples.Array[MultiplexId].SceneColor.rgb = RawSample[1].rgb * Weight;
}
#endif
}
#endif
#if COMPILE_SIGNAL_COLOR
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_REFLECTIONS_INPUT)
{
OutSamples.Array[0].SampleCount = RawSample[1].r == DENOISER_INVALID_CONFUSION_FACTOR ? 0 : 1;
OutSamples.Array[0].MissCount = RawSample[1].r == DENOISER_INVALID_CONFUSION_FACTOR ? 0 : (1 - RawSample[0].a);
OutSamples.Array[0].SceneColor = RawSample[0];
// max() because ray hit distance is < 0 when miss / not ray has been shot.
OutSampleFrequencies.Array[0].ConfusionFactor = RawSample[1].r;
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_REFLECTIONS_HISTORY)
{
if (bNormalizeSample)
{
OutSamples.Array[0].SampleCount = RawSample[1].r > 0 ? 1 : 0;
}
else
{
OutSamples.Array[0].SampleCount = RawSample[1].r;
}
OutSamples.Array[0].MissCount = OutSamples.Array[0].SampleCount * (1 - RawSample[0].a);
OutSamples.Array[0].SceneColor = OutSamples.Array[0].SampleCount * RawSample[0];
OutSampleFrequencies.Array[0].ConfusionFactor = RawSample[1].g;
}
#endif
#if 1
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_AO_INPUT)
{
OutSamples.Array[0].SampleCount = RawSample[1].r < 0 ? 0 : 1;
OutSamples.Array[0].MissCount = OutSamples.Array[0].SampleCount * RawSample[0].r;
OutSampleFrequencies.Array[0].WorldBluringRadius = RawSample[1].r;
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_AO_REJECTION)
{
if (bNormalizeSample)
{
OutSamples.Array[0].SampleCount = RawSample[0].g > 0 ? 1 : 0;
OutSamples.Array[0].MissCount = RawSample[0].g > 0 ? RawSample[0].r : 0;
#if SIGNAL_ARRAY_SIZE >= 2
OutSamples.Array[1].SampleCount = RawSample[0].a > 0 ? 1 : 0;
OutSamples.Array[1].MissCount = RawSample[0].a > 0 ? RawSample[0].b : 0;
#endif
}
else
{
OutSamples.Array[0].SampleCount = RawSample[0].g;
OutSamples.Array[0].MissCount = RawSample[0].g * RawSample[0].r;
#if SIGNAL_ARRAY_SIZE >= 2
OutSamples.Array[1].SampleCount = RawSample[0].a;
OutSamples.Array[1].MissCount = RawSample[0].a * RawSample[0].b;
#endif
}
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_AO_HISTORY)
{
if (bNormalizeSample)
{
OutSamples.Array[0].SampleCount = RawSample[0].g > 0 ? 1 : 0;
OutSamples.Array[0].MissCount = RawSample[0].g > 0 ? RawSample[0].r : 0;
}
else
{
OutSamples.Array[0].SampleCount = RawSample[0].g;
OutSamples.Array[0].MissCount = RawSample[0].g * RawSample[0].r;
}
OutSampleFrequencies.Array[0].WorldBluringRadius = RawSample[0].b;
}
#endif
#if COMPILE_SIGNAL_COLOR
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_DIFFUSE_INDIRECT_AND_AO_INPUT_NSPP)
{
OutSamples.Array[0].SampleCount = RawSample[1].g;
OutSamples.Array[0].MissCount = OutSamples.Array[0].SampleCount * (1 - RawSample[0].a);
OutSamples.Array[0].SceneColor = OutSamples.Array[0].SampleCount * RawSample[0];
OutSampleFrequencies.Array[0].ClosestHitDistance = ((RawSample[1].r == -1.0) ? 1.0e20 : RawSample[1].r);
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_DIFFUSE_INDIRECT_AND_AO_RECONSTRUCTION)
{
if (bNormalizeSample)
{
OutSamples.Array[0].SampleCount = RawSample[1].r > 0 ? 1 : 0;
}
else
{
OutSamples.Array[0].SampleCount = RawSample[1].r;
}
OutSamples.Array[0].MissCount = OutSamples.Array[0].SampleCount * (1 - RawSample[0].a);
OutSamples.Array[0].SceneColor = OutSamples.Array[0].SampleCount * RawSample[0];
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_DIFFUSE_INDIRECT_AND_AO_HISTORY)
{
if (bNormalizeSample)
{
OutSamples.Array[0].SampleCount = RawSample[1].r > 0 ? 1 : 0;
}
else
{
OutSamples.Array[0].SampleCount = RawSample[1].r;
}
OutSamples.Array[0].MissCount = OutSamples.Array[0].SampleCount * (1 - RawSample[0].a);
OutSamples.Array[0].SceneColor = OutSamples.Array[0].SampleCount * RawSample[0];
// Temporal analysis.
#if SIGNAL_ARRAY_SIZE >= 3
OutSamples.Array[1].SampleCount = OutSamples.Array[0].SampleCount;
OutSamples.Array[1].SceneColor.x = OutSamples.Array[1].SampleCount * RawSample[1].g;
OutSamples.Array[2].SampleCount = OutSamples.Array[0].SampleCount;
OutSamples.Array[2].SceneColor.x = OutSamples.Array[2].SampleCount * RawSample[1].b;
#endif
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_SSGI_INPUT)
{
OutSamples.Array[0].SampleCount = RawSample[0].a;
OutSamples.Array[0].MissCount = OutSamples.Array[0].SampleCount * RawSample[1].r;
OutSamples.Array[0].SceneColor.rgb = OutSamples.Array[0].SampleCount * RawSample[0].rgb;
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_SSGI_HISTORY_R11G11B10)
{
if (bNormalizeSample)
{
OutSamples.Array[0].SampleCount = RawSample[1].g > 0.0 ? 1.0 : 0.0;
}
else
{
OutSamples.Array[0].SampleCount = RawSample[1].g * 64.0;
}
OutSamples.Array[0].MissCount = OutSamples.Array[0].SampleCount * RawSample[1].r;
OutSamples.Array[0].SceneColor.rgb = OutSamples.Array[0].SampleCount * RawSample[0].rgb;
}
#endif
#if COMPILE_SIGNAL_COLOR_ARRAY >= 2
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_DIFFUSE_PROBE_HIERARCHY_INPUT)
{
OutSamples.Array[0].SampleCount = 1;
OutSamples.Array[0].ColorArray[0].rgb = OutSamples.Array[0].SampleCount * RawSample[0].rgb;
OutSamples.Array[0].ColorArray[1].rgb = OutSamples.Array[0].SampleCount * RawSample[1].rgb;
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_DIFFUSE_PROBE_HIERARCHY_HISTORY)
{
// Diffuse
if (bNormalizeSample)
{
OutSamples.Array[0].SampleCount = RawSample[2].r > 0.0 ? 1.0 : 0.0;
}
else
{
OutSamples.Array[0].SampleCount = RawSample[2].r * TARGETED_SAMPLE_COUNT;
}
OutSamples.Array[0].ColorArray[0].rgb = OutSamples.Array[0].SampleCount * RawSample[0].rgb;
OutSamples.Array[0].ColorArray[1].rgb = OutSamples.Array[0].SampleCount * RawSample[1].rgb;
}
#endif
#if COMPILE_SIGNAL_COLOR_SH
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_LUMEN_DIFFUSE_INPUT)
{
DecodeLumenDiffuseLighting(RawSample[0], RawSample[1], /* out */ OutSamples.Array[0].ColorSH);
float SampleCount = 1.0; // TODO(Denoiser)
OutSamples.Array[0] = MulSignal(OutSamples.Array[0], SampleCount);
OutSamples.Array[0].SampleCount = SampleCount;
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_LUMEN_DIFFUSE_HISTORY)
{
DecodeLumenDiffuseLighting(RawSample[0], RawSample[1], /* out */ OutSamples.Array[0].ColorSH);
float SampleCount = RawSample[0].a;
if (bNormalizeSample)
{
SampleCount = SampleCount > 0 ? 1 : 0;
}
else
{
SampleCount = RawSample[0].a;
}
OutSamples.Array[0] = MulSignal(OutSamples.Array[0], SampleCount);
OutSamples.Array[0].SampleCount = SampleCount;
}
#endif
} // DecodeMultiplexedSignalsFromFloat4()
void DecodeMultiplexedSignalsFromUint2(
const uint SignalBufferLayout,
const uint MultiplexedSampleId,
const bool bNormalizeSample,
uint2 RawSample[MAX_MULTIPLEXED_TEXTURES],
out FSSDSignalArray OutSamples,
out FSSDSignalFrequencyArray OutSampleFrequencies)
{
OutSamples = CreateSignalArrayFromScalarValue(0.0);
OutSampleFrequencies = CreateInvalidSignalFrequencyArray();
if (0)
{
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_PENUMBRA_INJESTION_NSPP)
{
UNROLL_N(MAX_SIGNAL_BATCH_SIZE)
for (uint BatchSignalId = 0; BatchSignalId < MAX_SIGNAL_BATCH_SIZE; BatchSignalId++)
{
uint MultiplexId = BatchSignalId;
uint EncodedData = MultiplexId % 2 ? RawSample[MultiplexId / 2].g : RawSample[MultiplexId / 2].r;
float MissCountRatio = (EncodedData & 0xFF) / 255.0;
float TransmissionDistanceRatio = ((EncodedData >> 8) & 0xFF) / 255.0;
float WorldBluringRadius = f16tof32(EncodedData >> 16);
float SampleCount = (WorldBluringRadius == -2.0 ? 0.0 : 1.0);
float MissCount = SampleCount * MissCountRatio;
float TransmissionDistance = TransmissionDistanceRatio;
// TODO(Denoiser): feed the actual number of sample.
OutSamples.Array[MultiplexId].SampleCount = SampleCount;
OutSamples.Array[MultiplexId].MissCount = MissCount;
OutSamples.Array[MultiplexId].TransmissionDistance = TransmissionDistance;
OutSampleFrequencies.Array[MultiplexId].WorldBluringRadius = WorldBluringRadius;
}
}
}
/** Decode input signal sample from raw float. */
void DecodeMultiplexedSignals(
const uint SignalBufferLayout,
const uint MultiplexedSampleId,
const bool bNormalizeSample,
FSSDCompressedMultiplexedSample CompressedSample,
out FSSDSignalArray OutSamples,
out FSSDSignalFrequencyArray OutSampleFrequencies)
#if CONFIG_SIGNAL_INPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_FLOAT4
{
DecodeMultiplexedSignalsFromFloat4(
SignalBufferLayout,
MultiplexedSampleId,
bNormalizeSample,
CompressedSample.VGPRArray,
/* out */ OutSamples,
/* out */ OutSampleFrequencies);
} // DecodeMultiplexedSignals()
#elif CONFIG_SIGNAL_INPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT2
{
FSSDSignalArray MultiplexedSamples = CreateSignalArrayFromScalarValue(0.0);
DecodeMultiplexedSignalsFromUint2(
SignalBufferLayout,
MultiplexedSampleId,
bNormalizeSample,
CompressedSample.VGPRArray,
/* out */ OutSamples,
/* out */ OutSampleFrequencies);
} // DecodeMultiplexedSignals()
#endif
/** Encode output signal sample. */
void EncodeMultiplexedSignals(
const uint SignalBufferLayout, const uint MultiplexCount,
FSSDSignalSample Sample[SIGNAL_ARRAY_SIZE],
FSSDSignalFrequency SampleFrequency[SIGNAL_ARRAY_SIZE],
out FSSDOutputRawSample OutRawSample[MAX_MULTIPLEXED_TEXTURES],
out uint OutBufferCount)
#if CONFIG_SIGNAL_OUTPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_FLOAT4
{
// Init all raw samples.
UNROLL_N(MAX_MULTIPLEXED_TEXTURES)
for (uint i = 0; i < MAX_MULTIPLEXED_TEXTURES; i++)
OutRawSample[i] = 0;
// Number of buffer the signal get encoded onto <= MAX_MULTIPLEXED_TEXTURES.
OutBufferCount = 1;
if (0)
{
// NOP
}
#if 1
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_PENUMBRA_HISTORY)
{
UNROLL
for (uint MultiplexId = 0; MultiplexId < MultiplexCount; MultiplexId++)
{
float NormalizationFactor = SafeRcp(Sample[MultiplexId].SampleCount);
float NormalizedTransmissionDistance = Sample[MultiplexId].TransmissionDistance * NormalizationFactor;
OutRawSample[MultiplexId] = float4(
Sample[MultiplexId].MissCount * NormalizationFactor,
Sample[MultiplexId].SampleCount,
SampleFrequency[MultiplexId].WorldBluringRadius,
NormalizedTransmissionDistance);
}
OutBufferCount = MultiplexCount;
}
#endif
#if COMPILE_SIGNAL_COLOR_ARRAY >= 2 && SIGNAL_ARRAY_SIZE >= 2
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_POLYCHROMATIC_PENUMBRA_HARMONIC_RECONSTRUCTION)
{
// diffuse harmonic
{
const uint MultiplexId = 0;
float NormalizationFactor = SafeRcp(Sample[MultiplexId].SampleCount);
OutRawSample[0].rgb = Sample[MultiplexId].ColorArray[0] * NormalizationFactor;
OutRawSample[0].a = Sample[MultiplexId].SampleCount;
OutRawSample[1].rgb = Sample[MultiplexId].ColorArray[1] * NormalizationFactor;
}
// specular harmonic
{
const uint MultiplexId = 1;
float NormalizationFactor = SafeRcp(Sample[1].SampleCount);
OutRawSample[2].rgb = Sample[MultiplexId].ColorArray[0] * NormalizationFactor;
OutRawSample[2].a = Sample[MultiplexId].SampleCount;
OutRawSample[3].rgb = Sample[MultiplexId].ColorArray[1] * NormalizationFactor;
}
OutBufferCount = 4;
}
#endif
#if COMPILE_SIGNAL_COLOR
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_POLYCHROMATIC_PENUMBRA_HISTORY)
{
// Encode diffuse harmonic
{
const uint MultiplexId = 0;
float NormalizationFactor = SafeRcp(Sample[MultiplexId].SampleCount);
OutRawSample[0].rgb = ClampColorForEncoding(Sample[MultiplexId].SceneColor.rgb * NormalizationFactor);
OutRawSample[0].a = Sample[MultiplexId].SampleCount;
}
// Encode specular harmonic
#if SIGNAL_ARRAY_SIZE >= 2
{
const uint MultiplexId = 1;
float NormalizationFactor = SafeRcp(Sample[MultiplexId].SampleCount);
OutRawSample[1].rgb = ClampColorForEncoding(Sample[MultiplexId].SceneColor.rgb * NormalizationFactor);
OutRawSample[1].a = Sample[MultiplexId].SampleCount;
}
#endif
OutBufferCount = 2;
}
#endif
#if COMPILE_SIGNAL_COLOR
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_REFLECTIONS_HISTORY)
{
float NormalizationFactor = SafeRcp(Sample[0].SampleCount);
// Outputs scene color to be compatible with a SSR output.
OutRawSample[0] = ClampColorForEncoding(Sample[0].SceneColor * NormalizationFactor);
OutRawSample[1].r = Sample[0].SampleCount;
OutRawSample[1].g = SampleFrequency[0].ConfusionFactor;
OutBufferCount = 2;
}
#endif
#if 1
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_AO_REJECTION)
{
// Outputs number of ray miss in red to be compatible as a SSAO output.
OutRawSample[0].r = Sample[0].SampleCount > 0 ? Sample[0].MissCount / Sample[0].SampleCount : 1.0;
OutRawSample[0].g = Sample[0].SampleCount;
#if SIGNAL_ARRAY_SIZE >= 2
if (MultiplexCount == 2)
{
OutRawSample[0].b = Sample[1].SampleCount > 0 ? Sample[1].MissCount / Sample[1].SampleCount : 1.0;
OutRawSample[0].a = Sample[1].SampleCount;
}
#endif
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_AO_HISTORY)
{
// Outputs number of ray miss in red to be compatible as a SSAO output.
OutRawSample[0].r = Sample[0].SampleCount > 0 ? Sample[0].MissCount / Sample[0].SampleCount : 1.0;
OutRawSample[0].g = Sample[0].SampleCount;
OutRawSample[0].b = SampleFrequency[0].WorldBluringRadius;
}
#endif
#if COMPILE_SIGNAL_COLOR
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_DIFFUSE_INDIRECT_AND_AO_RECONSTRUCTION)
{
float NormalizationFactor = SafeRcp(Sample[0].SampleCount);
OutRawSample[0] = ClampColorForEncoding(Sample[0].SceneColor * NormalizationFactor);
OutRawSample[1].r = Sample[0].SampleCount;
OutBufferCount = 2;
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_DIFFUSE_INDIRECT_AND_AO_HISTORY)
{
float NormalizationFactor = SafeRcp(Sample[0].SampleCount);
OutRawSample[0] = ClampColorForEncoding(Sample[0].SceneColor * NormalizationFactor);
OutRawSample[1].r = Sample[0].SampleCount;
OutBufferCount = 2;
// Temporal analysis.
#if SIGNAL_ARRAY_SIZE >= 3
if (MultiplexCount == 3)
{
OutRawSample[1].g = Sample[1].SceneColor.x * NormalizationFactor;
OutRawSample[1].b = Sample[2].SceneColor.x * NormalizationFactor;
}
#endif
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_SSGI_HISTORY_R11G11B10)
{
float NormalizationFactor = SafeRcp(Sample[0].SampleCount);
OutRawSample[0].rgb = ClampColorForEncoding(Sample[0].SceneColor * NormalizationFactor).rgb;
OutRawSample[1].g = saturate(Sample[0].SampleCount * rcp(64.0));
OutRawSample[1].r = Sample[0].MissCount * NormalizationFactor;
OutBufferCount = 2;
}
#endif
#if COMPILE_SIGNAL_COLOR_ARRAY >= 2
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_DIFFUSE_PROBE_HIERARCHY_HISTORY)
{
float NormalizationFactor = SafeRcp(Sample[0].SampleCount);
OutRawSample[0].rgb = ClampColorForEncoding(Sample[0].ColorArray[0] * NormalizationFactor);
OutRawSample[1].rgb = ClampColorForEncoding(Sample[0].ColorArray[1] * NormalizationFactor);
OutRawSample[2].r = saturate(Sample[0].SampleCount * rcp(TARGETED_SAMPLE_COUNT));
OutBufferCount = 3;
}
#endif
#if COMPILE_SIGNAL_COLOR_SH
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_LUMEN_DIFFUSE_HISTORY)
{
FSSDSignalSample NormalizedSample = NormalizeToOneSample(Sample[0]);
//FSSDSignalSample NormalizedSample = (Sample[0]);
EncodeLumenDiffuseLighting(NormalizedSample.ColorSH, /* out */ OutRawSample[0], /* out */ OutRawSample[1]);
OutRawSample[0].a = Sample[0].SampleCount;
OutBufferCount = 2;
}
#endif
} // EncodeMultiplexedSignals()
#elif CONFIG_SIGNAL_OUTPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_UINT2
{
// Init all raw samples.
UNROLL_N(MAX_MULTIPLEXED_TEXTURES)
for (uint i = 0; i < MAX_MULTIPLEXED_TEXTURES; i++)
OutRawSample[i] = 0;
// Number of buffer the signal get encoded onto <= MAX_MULTIPLEXED_TEXTURES.
OutBufferCount = 1;
if (0)
{
}
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_PENUMBRA_INJESTION_NSPP)
{
UNROLL
for (uint MultiplexId = 0; MultiplexId < MultiplexCount; MultiplexId++)
{
float MissCount = Sample[MultiplexId].MissCount;
float WorldBluringRadius = SampleFrequency[MultiplexId].WorldBluringRadius;
float TransmissionDistance = Sample[MultiplexId].TransmissionDistance;
float SampleCount = Sample[MultiplexId].SampleCount;
if (SampleCount == 0)
{
WorldBluringRadius = -2.0;
}
float MissCountRatio = MissCount * SafeRcp(SampleCount);
float TransmissionDistanceRatio = TransmissionDistance;
uint EncodedData = MissCountRatio * 255;
EncodedData |= (uint(TransmissionDistanceRatio * 255) << 8);
EncodedData |= (f32tof16(WorldBluringRadius) << 16);
if (MultiplexId % 2)
{
OutRawSample[MultiplexId / 2].g = EncodedData;
}
else
{
OutRawSample[MultiplexId / 2].r = EncodedData;
}
}
OutBufferCount = (MultiplexCount + 1) / 2;
}
#if COMPILE_SIGNAL_COLOR_SH
else if (SignalBufferLayout == SIGNAL_BUFFER_LAYOUT_DIFFUSE_INDIRECT_HARMONIC)
{
const uint EncodeOptions = (CONFIG_ENCODING_CLAMP_COLOR ? SSD_ENCODE_CLAMP_COLOR : 0) | SSD_ENCODE_NORMALIZE;
EncodeDiffuseSphericalHarmonicTexel(
Sample[0].SampleCount,
Sample[0].MissCount,
Sample[0].ColorSH,
EncodeOptions,
/* out */ OutRawSample);
OutBufferCount = 4;
}
#endif
} // EncodeMultiplexedSignals()
#else
#error Unimplemented.
#endif
/** Sample the raw of multiple input signals that have been multiplexed. */
FSSDCompressedMultiplexedSample SampleCompressedMultiplexedSignals(
FSSDTexture2D SignalBuffer0, FSSDTexture2D SignalBuffer1, FSSDTexture2D SignalBuffer2, FSSDTexture2D SignalBuffer3,
SamplerState Sampler, float2 UV, uint2 PixelCoord)
{
FSSDCompressedMultiplexedSample CompressedSample;
// Isolate the texture fetches to force lattency hiding, to outsmart compilers that tries to
// discard some of the texture fetches for instance when SampleCount == 0 in another texture.
ISOLATE
{
#if CONFIG_SIGNAL_INPUT_TEXTURE_TYPE == SIGNAL_TEXTURE_TYPE_FLOAT4
{
CompressedSample.VGPRArray[0] = SignalBuffer0.SampleLevel(Sampler, UV, 0.0);
CompressedSample.VGPRArray[1] = SignalBuffer1.SampleLevel(Sampler, UV, 0.0);
CompressedSample.VGPRArray[2] = SignalBuffer2.SampleLevel(Sampler, UV, 0.0);
CompressedSample.VGPRArray[3] = SignalBuffer3.SampleLevel(Sampler, UV, 0.0);
}
#elif CONFIG_SIGNAL_INPUT_TEXTURE_TYPE >= SIGNAL_TEXTURE_TYPE_UINT1 && CONFIG_SIGNAL_INPUT_TEXTURE_TYPE <= SIGNAL_TEXTURE_TYPE_UINT4
{
// TODO(Denoiser): Exposed the int3 instead as function parameter.
int3 Coord = int3(PixelCoord, 0);
CompressedSample.VGPRArray[0] = SignalBuffer0.Load(Coord);
CompressedSample.VGPRArray[1] = SignalBuffer1.Load(Coord);
CompressedSample.VGPRArray[2] = SignalBuffer2.Load(Coord);
CompressedSample.VGPRArray[3] = SignalBuffer3.Load(Coord);
}
#else
#error Unimplemented.
#endif
}
return CompressedSample;
}
/** Sample multiple input signals that have been multiplexed. */
void SampleMultiplexedSignals( // TODO
FSSDTexture2D SignalBuffer0, FSSDTexture2D SignalBuffer1, FSSDTexture2D SignalBuffer2, FSSDTexture2D SignalBuffer3,
SamplerState Sampler,
const uint SignalBufferLayout, const uint MultiplexedSampleId,
const bool bNormalizeSample,
float2 UV,
out FSSDSignalArray OutMultiplexedSamples,
out FSSDSignalFrequencyArray OutMultiplexedFrequencies)
{
uint2 PixelCoord = BufferUVToBufferPixelCoord(UV);
FSSDCompressedMultiplexedSample CompressedSample = SampleCompressedMultiplexedSignals(
SignalBuffer0, SignalBuffer1, SignalBuffer2, SignalBuffer3,
Sampler, UV, PixelCoord);
DecodeMultiplexedSignals(
SignalBufferLayout, MultiplexedSampleId, bNormalizeSample, CompressedSample,
/* out */ OutMultiplexedSamples,
/* out */ OutMultiplexedFrequencies);
}
/** Outputs multiplexed signal. */
void OutputMultiplexedSignal(
FSSDRWTexture2D OutputSignalBuffer0,
FSSDRWTexture2D OutputSignalBuffer1,
FSSDRWTexture2D OutputSignalBuffer2,
FSSDRWTexture2D OutputSignalBuffer3,
const uint SignalBufferLayout, const uint MultiplexCount,
const uint2 PixelPosition,
FSSDSignalArray MultiplexedSamples,
FSSDSignalFrequencyArray MultiplexedFrequencies)
{
// Encode the output signal.
FSSDOutputRawSample RawSample[MAX_MULTIPLEXED_TEXTURES];
uint BufferCount;
EncodeMultiplexedSignals(
SignalBufferLayout, MultiplexCount,
MultiplexedSamples.Array,
MultiplexedFrequencies.Array,
/* out */ RawSample, /* out */ BufferCount);
// Output the raw encoded sample according to number of RT they requires.
if (BufferCount >= 1)
OutputSignalBuffer0[PixelPosition] = RawSample[0];
if (BufferCount >= 2)
OutputSignalBuffer1[PixelPosition] = RawSample[1];
if (BufferCount >= 3)
OutputSignalBuffer2[PixelPosition] = RawSample[2];
if (BufferCount >= 4)
OutputSignalBuffer3[PixelPosition] = RawSample[3];
}