Files
UnrealEngine/Engine/Plugins/Media/ImgMedia/Shaders/Private/ExrSwizzler.usf
2025-05-18 13:04:45 +08:00

194 lines
5.4 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "/Engine/Private/Common.ush"
#include "/Engine/Private/GammaCorrectionCommon.ush"
#define NUM_CHANNELS (PERMUTATION_CHANNELS + 1)
#if PARTIAL_TILES
struct FTileDesc
{
int2 TileResolution;
uint BufferOffset;
int AlignPadding;
};
#endif
/** The unswizzled buffer packed into 4 byte buffer stride. */
StructuredBuffer<uint> UnswizzledBuffer;
#if PARTIAL_TILES
/** The unswizzled buffer packed into 4 byte buffer stride. */
StructuredBuffer<FTileDesc> TileDescBuffer;
#endif
/** Texture size that the buffer is supposed to be unpacked to. */
int2 TextureSize;
/** Size of tiles that represent this texture. */
int2 TileSize;
/** Total number of tiles in X and Y direction for the current mip level. */
int2 NumTiles;
/** Number of channels per pixel. */
int NumChannels;
/** Flag to enable color space transformations. */
uint bApplyColorTransform;
/** Source encoding to linearize. */
uint EOTF;
/** Color space transformation matrix, from source to working. */
float4x4 ColorSpaceMatrix;
// Same definitions as MediaShaders.usf
#define UE_Color_EEncoding_Linear 1u
#define UE_Color_EEncoding_sRGB 2u
#define UE_Color_EEncoding_ST2084 3u
#define UE_Color_EEncoding_SLog3 12u
float3 ApplyColorTransform(float3 Color, float3x3 InColorSpaceMatrix, uint InEOTF)
{
// Linearize
switch(InEOTF)
{
case UE_Color_EEncoding_sRGB: Color = sRGBToLinear(Color); break;
case UE_Color_EEncoding_ST2084: Color = ST2084ToLinear(Color); break;
case UE_Color_EEncoding_SLog3: Color = SLog3ToLinear(Color); break;
default: break;
}
// Adjust colorspace
return mul(InColorSpaceMatrix, Color);
}
/** Unpacks data from the provided structured buffer. */
half GetBufferValue(int Offset, int2 TextureSize, int ChannelIndex)
{
// the location as if it would've been if the buffer was unpacked.
int UnpackedLocation = Offset + TextureSize.x * ChannelIndex;
// Byte offset within the 4 byte packed value.
int Remainder = UnpackedLocation % 2;
// Position in a packed buffer.
int PackedPosition = (UnpackedLocation - Remainder) >> 1;
uint PackedValue = (UnswizzledBuffer[PackedPosition] >> (16 * Remainder)) & 0xffff;
// Convert from uint32 to f16
return (half)f16tof32(PackedValue);
}
/** Vertex Shader. */
void MainVS(
in float4 InPosition : ATTRIBUTE0,
in float2 InTexCoord : ATTRIBUTE1,
out noperspective float4 OutUVAndScreenPos : TEXCOORD0,
out float4 OutPosition : SV_POSITION)
{
DrawRectangle(InPosition, InTexCoord, OutPosition, OutUVAndScreenPos);
}
#if PARTIAL_TILES
void GetStartScanlinePosition_PartialTiles(in int2 PixelPos, out int2 SampleSize, out int StartPosition)
{
int2 TileCoord = int2(ceil(PixelPos.x / TileSize.x), ceil(PixelPos.y / TileSize.y));
FTileDesc TileDesc = TileDescBuffer[TileCoord.y * NumTiles.x + TileCoord.x];
SampleSize = TileDesc.TileResolution;
int xCoord = (PixelPos.x) % TileSize.x;
int yCoord = (PixelPos.y) % TileSize.y;
// Padding in buffer elements (uint)
const int TilePadding = 10;
// Offset is in bytes while our buffer is a packed uint16 into uint32. Therefore divide by 2.
int PreviousTilesOffset = TileDesc.BufferOffset / 2;
// Current tile position.
StartPosition = PreviousTilesOffset + yCoord * TileDesc.TileResolution.x * NumChannels + xCoord + TilePadding;
}
#endif
void GetStartScanlinePosition(in int2 PixelPos, out int2 SampleSize, out int StartPosition)
{
// Depending on the EXR file it could contain multi-channel data.
#if RENDER_TILES
SampleSize = TileSize;
int xCoord = (PixelPos.x) % TileSize.x;
int yCoord = (PixelPos.y) % TileSize.y;
int TileX = floor((PixelPos.x) / TileSize.x);
int TileY = floor((PixelPos.y) / TileSize.y);
// Padding in buffer elements (uint)
const int TilePadding = 10;
// Current tile position.
int TileBufferStride = TileSize.x * TileSize.y * NumChannels;
int PreviousTilesOffset = (NumTiles.x * TileY + TileX) * TileBufferStride;
StartPosition = PreviousTilesOffset + yCoord * TileSize.x * NumChannels + xCoord + (TileY * NumTiles.x + TileX + 1) * TilePadding;
#else
SampleSize.x = TextureSize.x;
SampleSize.y = TextureSize.y;
// Padding in bytes
const int TilePadding = 4;
// Current scanline position.
StartPosition = PixelPos.y * TextureSize.x * NumChannels + PixelPos.x + (PixelPos.y + 1) * 4;
#endif //RENDER_TILES
}
/** Pixel Shader. */
half4 MainPS(noperspective float4 UVAndScreenPos : TEXCOORD0) : SV_Target0
{
float2 UV = UVAndScreenPos.xy;
int2 SampleSize;
int2 PixelPos = UV * TextureSize;
int StartBufferPosition;
#if PARTIAL_TILES
GetStartScanlinePosition_PartialTiles(PixelPos, SampleSize, StartBufferPosition);
#else
GetStartScanlinePosition(PixelPos, SampleSize, StartBufferPosition);
#endif
int ChannelIndex = 0;
half4 Color = half4(0.0f, 0.0f, 0.0f, 1.0f);
#if NUM_CHANNELS == 4
Color.a = GetBufferValue(StartBufferPosition, SampleSize, ChannelIndex++);
#endif
#if NUM_CHANNELS >= 3
Color.b = GetBufferValue(StartBufferPosition, SampleSize, ChannelIndex++);
#endif
#if NUM_CHANNELS >= 2
Color.g = GetBufferValue(StartBufferPosition, SampleSize, ChannelIndex++);
#endif
#if NUM_CHANNELS >= 1
Color.r = GetBufferValue(StartBufferPosition, SampleSize, ChannelIndex++);
#endif
// Special case for single channel EXRs: we convert to grayscale by duplicating the red channel.
#if NUM_CHANNELS == 1
Color.rgb = Color.r;
#endif
if(bApplyColorTransform)
{
Color.rgb = ApplyColorTransform(Color.rgb, (float3x3)ColorSpaceMatrix, EOTF);
}
return Color;
}