Files
UnrealEngine/Engine/Source/Runtime/RHI/Public/RHISurfaceDataConversion.h
2025-05-18 13:04:45 +08:00

1050 lines
29 KiB
C

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
RHISurfaceDataConversion.h: RHI surface data conversions.
=============================================================================*/
#pragma once
#include "Math/Float16Color.h"
#include "Math/PackedVector.h"
#include "Math/Plane.h"
#include "Math/UnrealMathUtility.h"
#include "RHI.h"
#include "RHITypes.h"
namespace
{
/** Helper for accessing R10G10B10A2 colors. */
struct FRHIR10G10B10A2
{
uint32 R : 10;
uint32 G : 10;
uint32 B : 10;
uint32 A : 2;
};
/** Helper for accessing R16G16B16A16 colors. */
struct FRHIRGBA16
{
uint16 R;
uint16 G;
uint16 B;
uint16 A;
};
/** Helper for accessing R16G16 colors. */
struct FRHIRG16
{
uint16 R;
uint16 G;
};
inline void ConvertRawR16DataToFColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out)
{
// e.g. shadow maps
for (uint32 Y = 0; Y < Height; Y++)
{
uint16* SrcPtr = (uint16*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
uint16 Value16 = *SrcPtr;
int Value = FColor::Requantize16to8(Value16);
*DestPtr = FColor(Value, Value, Value);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawR8G8B8A8DataToFColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out)
{
for (uint32 Y = 0; Y < Height; Y++)
{
FColor* SrcPtr = (FColor*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FColor(SrcPtr->B, SrcPtr->G, SrcPtr->R, SrcPtr->A);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawB8G8R8A8DataToFColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out)
{
const uint32 DstPitch = Width * sizeof(FColor);
// If source & dest pitch matches, perform a single memcpy.
if (DstPitch == SrcPitch)
{
FPlatformMemory::Memcpy(Out, In, Width * Height * sizeof(FColor));
}
else
{
check(SrcPitch > DstPitch);
// Need to copy row wise since the Pitch does not match the Width.
for (uint32 Y = 0; Y < Height; Y++)
{
FColor* SrcPtr = (FColor*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
FMemory::Memcpy(DestPtr, SrcPtr, DstPitch);
}
}
}
inline void ConvertRawR16G16B16A16FDataToFFloat16Color(uint32 Width, uint32 Height, uint8* In, uint32 SrcPitch, FFloat16Color* Out)
{
const uint32 DstPitch = Width * sizeof(FFloat16Color);
// If source & dest pitch matches, perform a single memcpy.
if (DstPitch == SrcPitch)
{
FPlatformMemory::Memcpy(Out, In, Width * Height * sizeof(FFloat16Color));
}
else
{
check(SrcPitch > DstPitch);
// Need to copy row wise since the Pitch does not match the Width.
for (uint32 Y = 0; Y < Height; Y++)
{
FFloat16Color* SrcPtr = (FFloat16Color*)(In + Y * SrcPitch);
FFloat16Color* DestPtr = Out + Y * Width;
FMemory::Memcpy(DestPtr, SrcPtr, DstPitch);
}
}
}
inline void ConvertRawR10G10B10A2DataToFColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out)
{
for (uint32 Y = 0; Y < Height; Y++)
{
FRHIR10G10B10A2* SrcPtr = (FRHIR10G10B10A2*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FColor::MakeRequantizeFrom1010102(
SrcPtr->R,
SrcPtr->G,
SrcPtr->B,
SrcPtr->A
);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawB10G10R10A2DataToFColor(uint32 Width, uint32 Height, uint8* In, uint32 SrcPitch, FColor* Out)
{
for (uint32 Y = 0; Y < Height; Y++)
{
FRHIR10G10B10A2* SrcPtr = (FRHIR10G10B10A2*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FColor::MakeRequantizeFrom1010102(
SrcPtr->B,
SrcPtr->G,
SrcPtr->R,
SrcPtr->A
);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawR16G16B16A16FDataToFColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out, bool LinearToGamma)
{
FPlane MinValue(0.0f, 0.0f, 0.0f, 0.0f),
MaxValue(1.0f, 1.0f, 1.0f, 1.0f);
check(sizeof(FFloat16) == sizeof(uint16));
for (uint32 Y = 0; Y < Height; Y++)
{
FFloat16* SrcPtr = (FFloat16*)(In + Y * SrcPitch);
for (uint32 X = 0; X < Width; X++)
{
MinValue.X = FMath::Min<float>(SrcPtr[0], MinValue.X);
MinValue.Y = FMath::Min<float>(SrcPtr[1], MinValue.Y);
MinValue.Z = FMath::Min<float>(SrcPtr[2], MinValue.Z);
MinValue.W = FMath::Min<float>(SrcPtr[3], MinValue.W);
MaxValue.X = FMath::Max<float>(SrcPtr[0], MaxValue.X);
MaxValue.Y = FMath::Max<float>(SrcPtr[1], MaxValue.Y);
MaxValue.Z = FMath::Max<float>(SrcPtr[2], MaxValue.Z);
MaxValue.W = FMath::Max<float>(SrcPtr[3], MaxValue.W);
SrcPtr += 4;
}
}
for (uint32 Y = 0; Y < Height; Y++)
{
FFloat16* SrcPtr = (FFloat16*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr =
FLinearColor(
(SrcPtr[0] - MinValue.X) / (MaxValue.X - MinValue.X),
(SrcPtr[1] - MinValue.Y) / (MaxValue.Y - MinValue.Y),
(SrcPtr[2] - MinValue.Z) / (MaxValue.Z - MinValue.Z),
(SrcPtr[3] - MinValue.W) / (MaxValue.W - MinValue.W)
).ToFColor(LinearToGamma);
SrcPtr += 4;
++DestPtr;
}
}
}
inline void ConvertRawR11G11B10DataToFColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out, bool LinearToGamma)
{
check(sizeof(FFloat3Packed) == sizeof(uint32));
for (uint32 Y = 0; Y < Height; Y++)
{
FFloat3Packed* SrcPtr = (FFloat3Packed*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
FLinearColor Value = (*SrcPtr).ToLinearColor();
*DestPtr = Value.ToFColor(LinearToGamma);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawR9G9B9E5DataToFColor(uint32 Width, uint32 Height, uint8* In, uint32 SrcPitch, FColor* Out, bool LinearToGamma)
{
check(sizeof(FFloat3PackedSE) == sizeof(uint32));
for (uint32 Y = 0; Y < Height; Y++)
{
FFloat3PackedSE* SrcPtr = (FFloat3PackedSE*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
FLinearColor Value = (*SrcPtr).ToLinearColor();
*DestPtr = Value.ToFColor(LinearToGamma);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawR32G32B32A32DataToFColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out, bool LinearToGamma)
{
FPlane MinValue(0.0f, 0.0f, 0.0f, 0.0f);
FPlane MaxValue(1.0f, 1.0f, 1.0f, 1.0f);
for (uint32 Y = 0; Y < Height; Y++)
{
float* SrcPtr = (float*)(In + Y * SrcPitch);
for (uint32 X = 0; X < Width; X++)
{
MinValue.X = FMath::Min<float>(SrcPtr[0], MinValue.X);
MinValue.Y = FMath::Min<float>(SrcPtr[1], MinValue.Y);
MinValue.Z = FMath::Min<float>(SrcPtr[2], MinValue.Z);
MinValue.W = FMath::Min<float>(SrcPtr[3], MinValue.W);
MaxValue.X = FMath::Max<float>(SrcPtr[0], MaxValue.X);
MaxValue.Y = FMath::Max<float>(SrcPtr[1], MaxValue.Y);
MaxValue.Z = FMath::Max<float>(SrcPtr[2], MaxValue.Z);
MaxValue.W = FMath::Max<float>(SrcPtr[3], MaxValue.W);
SrcPtr += 4;
}
}
for (uint32 Y = 0; Y < Height; Y++)
{
float* SrcPtr = (float*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr =
FLinearColor(
(SrcPtr[0] - MinValue.X) / (MaxValue.X - MinValue.X),
(SrcPtr[1] - MinValue.Y) / (MaxValue.Y - MinValue.Y),
(SrcPtr[2] - MinValue.Z) / (MaxValue.Z - MinValue.Z),
(SrcPtr[3] - MinValue.W) / (MaxValue.W - MinValue.W)
).ToFColor(LinearToGamma);
SrcPtr += 4;
++DestPtr;
}
}
}
inline void ConvertRawR24G8DataToFColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out, FReadSurfaceDataFlags InFlags)
{
bool bLinearToGamma = InFlags.GetLinearToGamma();
// Depth stencil
for (uint32 Y = 0; Y < Height; Y++)
{
uint32* SrcPtr = (uint32 *)In;
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
FColor NormalizedColor;
if (InFlags.GetOutputStencil())
{
uint8 DeviceStencil = (*SrcPtr & 0xFF000000) >> 24;
NormalizedColor = FColor(DeviceStencil, DeviceStencil, DeviceStencil, 0xFF);
}
else
{
float DeviceZ = (*SrcPtr & 0xffffff) / (float)(1 << 24);
float LinearValue = FMath::Min(InFlags.ComputeNormalizedDepth(DeviceZ), 1.0f);
NormalizedColor = FLinearColor(LinearValue, LinearValue, LinearValue, 0).ToFColor(bLinearToGamma);
}
*DestPtr = NormalizedColor;
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawDepthStencil64DataToFColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out, FReadSurfaceDataFlags InFlags)
{
bool bLinearToGamma = InFlags.GetLinearToGamma();
for (uint32 Y = 0; Y < Height; Y++)
{
float* SrcPtr = (float *)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
float DeviceZ = (*SrcPtr);
float LinearValue = FMath::Min(InFlags.ComputeNormalizedDepth(DeviceZ), 1.0f);
*DestPtr = FLinearColor(LinearValue, LinearValue, LinearValue, 0).ToFColor(bLinearToGamma);
SrcPtr += 1; // todo: copies only depth, need to check how this format is read
++DestPtr;
UE_LOG(LogRHI, Warning, TEXT("CPU read of R32G8X24 is not tested and may not function."));
}
}
}
inline void ConvertRawR16G16B16A16DataToFColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out, bool bLinearToGamma = false)
{
for (uint32 Y = 0; Y < Height; Y++)
{
FRHIRGBA16* SrcPtr = (FRHIRGBA16*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FLinearColor(
FColor::DequantizeUNorm16ToFloat(SrcPtr->R),
FColor::DequantizeUNorm16ToFloat(SrcPtr->G),
FColor::DequantizeUNorm16ToFloat(SrcPtr->B),
FColor::DequantizeUNorm16ToFloat(SrcPtr->A)
).ToFColor(bLinearToGamma);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawR16G16DataToFColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out)
{
for (uint32 Y = 0; Y < Height; Y++)
{
FRHIRG16* SrcPtr = (FRHIRG16*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FColor(
FColor::Requantize16to8(SrcPtr->R),
FColor::Requantize16to8(SrcPtr->G),
0);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawR8DataToFColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out)
{
for (uint32 Y = 0; Y < Height; Y++)
{
uint8* SrcPtr = (uint8*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FColor(*SrcPtr, *SrcPtr, *SrcPtr, *SrcPtr);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawR8G8DataToFColor(uint32 Width, uint32 Height, uint8* In, uint32 SrcPitch, FColor* Out)
{
for (uint32 Y = 0; Y < Height; Y++)
{
uint8* SrcPtr = (uint8*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FColor(*SrcPtr, *(SrcPtr + 1), 0);
SrcPtr += 2;
++DestPtr;
}
}
}
inline void ConvertRawD32S8DataToFColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out, FReadSurfaceDataFlags InFlags)
{
bool bLinearToGamma = InFlags.GetLinearToGamma();
// Depth
if (!InFlags.GetOutputStencil())
{
for (uint32 Y = 0; Y < Height; Y++)
{
uint32* SrcPtr = (uint32*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
float DeviceZ = *SrcPtr;
float LinearValue = FMath::Min(InFlags.ComputeNormalizedDepth(DeviceZ), 1.0f);
*DestPtr = FLinearColor(LinearValue, LinearValue, LinearValue, 0).ToFColor(bLinearToGamma);
++DestPtr;
++SrcPtr;
}
}
}
// Stencil
else
{
// Depth stencil
for (uint32 Y = 0; Y < Height; Y++)
{
uint8* SrcPtr = (uint8*)(In + Y * SrcPitch);
FColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
uint8 DeviceStencil = *SrcPtr;
*DestPtr = FColor(DeviceStencil, DeviceStencil, DeviceStencil, 0xFF);
++SrcPtr;
++DestPtr;
}
}
}
}
// Linear functions
inline void ConvertRawR16UDataToFLinearColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FLinearColor* Out)
{
// e.g. shadow maps
for (uint32 Y = 0; Y < Height; Y++)
{
uint16* SrcPtr = (uint16*)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
uint16 Value16 = *SrcPtr;
float Value = Value16 * (1.f/0xffff);
*DestPtr = FLinearColor(Value, Value, Value);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawR16FDataToFLinearColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FLinearColor* Out)
{
// e.g. shadow maps
for (uint32 Y = 0; Y < Height; Y++)
{
FFloat16 * SrcPtr = (FFloat16 *)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
float Value = SrcPtr->GetFloat();
*DestPtr = FLinearColor(Value, Value, Value);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawR8G8B8A8DataToFLinearColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FLinearColor* Out)
{
// Read the data out of the buffer, converting it from ABGR to ARGB.
for (uint32 Y = 0; Y < Height; Y++)
{
FColor* SrcPtr = (FColor*)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
FColor sRGBColor = FColor(SrcPtr->B, SrcPtr->G, SrcPtr->R, SrcPtr->A); // swap RB
// FLinearColor(FColor) does SRGB -> Linear
*DestPtr = FLinearColor(sRGBColor);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawB8G8R8A8DataToFLinearColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FLinearColor* Out)
{
for (uint32 Y = 0; Y < Height; Y++)
{
FColor* SrcPtr = (FColor*)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
// FLinearColor(FColor) does SRGB -> Linear
*DestPtr = FLinearColor(*SrcPtr);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawA2B10G10R10DataToFLinearColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FLinearColor* Out)
{
// Read the data out of the buffer, converting it from R10G10B10A2 to FLinearColor.
for (uint32 Y = 0; Y < Height; Y++)
{
FRHIR10G10B10A2* SrcPtr = (FRHIR10G10B10A2*)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FLinearColor(
(float)SrcPtr->R / 1023.0f,
(float)SrcPtr->G / 1023.0f,
(float)SrcPtr->B / 1023.0f,
(float)SrcPtr->A / 3.0f
);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawR16G16B16A16FDataToFLinearColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FLinearColor* Out, FReadSurfaceDataFlags InFlags)
{
if (InFlags.GetCompressionMode() == RCM_MinMax)
{
for (uint32 Y = 0; Y < Height; Y++)
{
FFloat16* SrcPtr = (FFloat16*)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FLinearColor((float)SrcPtr[0], (float)SrcPtr[1], (float)SrcPtr[2], (float)SrcPtr[3]);
++DestPtr;
SrcPtr += 4;
}
}
}
else
{
FPlane MinValue(0.0f, 0.0f, 0.0f, 0.0f);
FPlane MaxValue(1.0f, 1.0f, 1.0f, 1.0f);
check(sizeof(FFloat16) == sizeof(uint16));
for (uint32 Y = 0; Y < Height; Y++)
{
FFloat16* SrcPtr = (FFloat16*)(In + Y * SrcPitch);
for (uint32 X = 0; X < Width; X++)
{
MinValue.X = FMath::Min<float>(SrcPtr[0], MinValue.X);
MinValue.Y = FMath::Min<float>(SrcPtr[1], MinValue.Y);
MinValue.Z = FMath::Min<float>(SrcPtr[2], MinValue.Z);
MinValue.W = FMath::Min<float>(SrcPtr[3], MinValue.W);
MaxValue.X = FMath::Max<float>(SrcPtr[0], MaxValue.X);
MaxValue.Y = FMath::Max<float>(SrcPtr[1], MaxValue.Y);
MaxValue.Z = FMath::Max<float>(SrcPtr[2], MaxValue.Z);
MaxValue.W = FMath::Max<float>(SrcPtr[3], MaxValue.W);
SrcPtr += 4;
}
}
for (uint32 Y = 0; Y < Height; Y++)
{
FFloat16* SrcPtr = (FFloat16*)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FLinearColor(
(SrcPtr[0] - MinValue.X) / (MaxValue.X - MinValue.X),
(SrcPtr[1] - MinValue.Y) / (MaxValue.Y - MinValue.Y),
(SrcPtr[2] - MinValue.Z) / (MaxValue.Z - MinValue.Z),
(SrcPtr[3] - MinValue.W) / (MaxValue.W - MinValue.W)
);
++DestPtr;
SrcPtr += 4;
}
}
}
}
inline void ConvertRawR11G11B10FDataToFLinearColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FLinearColor* Out)
{
check(sizeof(FFloat3Packed) == sizeof(uint32));
for (uint32 Y = 0; Y < Height; Y++)
{
FFloat3Packed* SrcPtr = (FFloat3Packed*)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = (*SrcPtr).ToLinearColor();
++DestPtr;
++SrcPtr;
}
}
}
inline void ConvertRawR32G32B32A32DataToFLinearColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FLinearColor* Out, FReadSurfaceDataFlags InFlags)
{
if (InFlags.GetCompressionMode() == RCM_MinMax)
{
// Copy data directly, respecting existing min-max values
FLinearColor* SrcPtr = (FLinearColor*)In;
FLinearColor* DestPtr = (FLinearColor*)Out;
const int32 ImageSize = sizeof(FLinearColor) * Height * Width;
FMemory::Memcpy(DestPtr, SrcPtr, ImageSize);
}
else
{
// Normalize data
FPlane MinValue(0.0f, 0.0f, 0.0f, 0.0f);
FPlane MaxValue(1.0f, 1.0f, 1.0f, 1.0f);
for (uint32 Y = 0; Y < Height; Y++)
{
float* SrcPtr = (float*)(In + Y * SrcPitch);
for (uint32 X = 0; X < Width; X++)
{
MinValue.X = FMath::Min<float>(SrcPtr[0], MinValue.X);
MinValue.Y = FMath::Min<float>(SrcPtr[1], MinValue.Y);
MinValue.Z = FMath::Min<float>(SrcPtr[2], MinValue.Z);
MinValue.W = FMath::Min<float>(SrcPtr[3], MinValue.W);
MaxValue.X = FMath::Max<float>(SrcPtr[0], MaxValue.X);
MaxValue.Y = FMath::Max<float>(SrcPtr[1], MaxValue.Y);
MaxValue.Z = FMath::Max<float>(SrcPtr[2], MaxValue.Z);
MaxValue.W = FMath::Max<float>(SrcPtr[3], MaxValue.W);
SrcPtr += 4;
}
}
float* SrcPtr = (float*)In;
for (uint32 Y = 0; Y < Height; Y++)
{
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FLinearColor(
(SrcPtr[0] - MinValue.X) / (MaxValue.X - MinValue.X),
(SrcPtr[1] - MinValue.Y) / (MaxValue.Y - MinValue.Y),
(SrcPtr[2] - MinValue.Z) / (MaxValue.Z - MinValue.Z),
(SrcPtr[3] - MinValue.W) / (MaxValue.W - MinValue.W)
);
++DestPtr;
SrcPtr += 4;
}
}
}
}
inline void ConvertRawR24G8DataToFLinearColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FLinearColor* Out, FReadSurfaceDataFlags InFlags)
{
// Depth stencil
for (uint32 Y = 0; Y < Height; Y++)
{
uint32* SrcPtr = (uint32 *)In;
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
float DeviceStencil = 0.0f;
DeviceStencil = (float)((*SrcPtr & 0xFF000000) >> 24) / 255.0f;
float DeviceZ = (*SrcPtr & 0xffffff) / (float)(1 << 24);
float LinearValue = FMath::Min(InFlags.ComputeNormalizedDepth(DeviceZ), 1.0f);
*DestPtr = FLinearColor(LinearValue, DeviceStencil, 0.0f, 0.0f);
++DestPtr;
++SrcPtr;
}
}
}
inline void ConvertRawDepthStencil64DataToFLinearColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FLinearColor* Out, FReadSurfaceDataFlags InFlags)
{
// Depth stencil
for (uint32 Y = 0; Y < Height; Y++)
{
uint8* SrcStart = (uint8 *)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
float DeviceZ = *((float *)(SrcStart));
float LinearValue = FMath::Min(InFlags.ComputeNormalizedDepth(DeviceZ), 1.0f);
float DeviceStencil = (float)(*(SrcStart + 4)) / 255.0f;
*DestPtr = FLinearColor(LinearValue, DeviceStencil, 0.0f, 0.0f);
SrcStart += 8; //64 bit format with the last 24 bit ignore
++DestPtr;
}
}
}
inline void ConvertRawR16G16B16A16DataToFLinearColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FLinearColor* Out)
{
// Read the data out of the buffer, converting it to FLinearColor.
for (uint32 Y = 0; Y < Height; Y++)
{
FRHIRGBA16* SrcPtr = (FRHIRGBA16*)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FLinearColor(
(float)SrcPtr->R / 65535.0f,
(float)SrcPtr->G / 65535.0f,
(float)SrcPtr->B / 65535.0f,
(float)SrcPtr->A / 65535.0f
);
++SrcPtr;
++DestPtr;
}
}
}
inline void ConvertRawR16G16DataToFLinearColor(uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FLinearColor* Out)
{
// Read the data out of the buffer, converting it to FLinearColor.
for (uint32 Y = 0; Y < Height; Y++)
{
FRHIRG16* SrcPtr = (FRHIRG16*)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FLinearColor(
(float)SrcPtr->R / 65535.0f,
(float)SrcPtr->G / 65535.0f,
0);
++SrcPtr;
++DestPtr;
}
}
}
bool ConvertRAWSurfaceDataToFLinearColor(EPixelFormat Format, uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FLinearColor* Out, FReadSurfaceDataFlags InFlags)
{
// InFlags.GetLinearToGamma() is ignored by the FLinearColor reader
// Flags RCM_MinMax means pass the values out unchanged
// default flags RCM_UNorm rescales them to [0,1] if they were outside that range
if (Format == PF_G16 || Format == PF_R16_UINT )
{
ConvertRawR16UDataToFLinearColor(Width, Height, In, SrcPitch, Out);
return true;
}
else if (Format == PF_R16F || Format == PF_R16F_FILTER)
{
ConvertRawR16FDataToFLinearColor(Width, Height, In, SrcPitch, Out);
return true;
}
else if (Format == PF_R8G8B8A8)
{
ConvertRawR8G8B8A8DataToFLinearColor(Width, Height, In, SrcPitch, Out);
return true;
}
else if (Format == PF_B8G8R8A8)
{
ConvertRawB8G8R8A8DataToFLinearColor(Width, Height, In, SrcPitch, Out);
return true;
}
else if (Format == PF_A2B10G10R10)
{
ConvertRawA2B10G10R10DataToFLinearColor(Width, Height, In, SrcPitch, Out);
return true;
}
else if (Format == PF_FloatRGBA)
{
ConvertRawR16G16B16A16FDataToFLinearColor(Width, Height, In, SrcPitch, Out, InFlags);
return true;
}
else if (Format == PF_FloatRGB || Format == PF_FloatR11G11B10)
{
// assume FloatRGB == PF_FloatR11G11B10 always here
check( GPixelFormats[Format].BlockBytes == 4 );
ConvertRawR11G11B10FDataToFLinearColor(Width, Height, In, SrcPitch, Out);
return true;
}
else if (Format == PF_A32B32G32R32F)
{
ConvertRawR32G32B32A32DataToFLinearColor(Width, Height, In, SrcPitch, Out, InFlags);
return true;
}
else if ( Format == PF_D24 ||
( (Format == PF_X24_G8 || Format == PF_DepthStencil ) && GPixelFormats[Format].BlockBytes == 4 )
)
{
// see CVarD3D11UseD24/CVarD3D12UseD24
ConvertRawR24G8DataToFLinearColor(Width, Height, In, SrcPitch, Out, InFlags);
return true;
}
else if ( (Format == PF_X24_G8 || Format == PF_DepthStencil ) && GPixelFormats[Format].BlockBytes > 4 )
{
// @@ D3D 11/12 different?
/**
D3D11 and 12 formats are almost the same, one difference :
DepthStencil formats are interleaved DepthStencil formats are planar.
For example a format of 24 bits of depth, 8 bits of stencil would be
stored in the format 24/8/24/8... etc in Direct3D 11, but as 24/24/24...
followed by 8/8/8... in Direct3D 12. Note that each plane is its own
subresource in D3D12
**/
ConvertRawDepthStencil64DataToFLinearColor(Width, Height, In, SrcPitch, Out, InFlags);
return true;
}
else if (Format == PF_A16B16G16R16)
{
ConvertRawR16G16B16A16DataToFLinearColor(Width, Height, In, SrcPitch, Out);
return true;
}
else if (Format == PF_G16R16)
{
ConvertRawR16G16DataToFLinearColor(Width, Height, In, SrcPitch, Out);
return true;
}
else if (Format == PF_G16R16F)
{
// Read the data out of the buffer, converting it to FLinearColor.
for (uint32 Y = 0; Y < Height; Y++)
{
FFloat16 * SrcPtr = (FFloat16*)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FLinearColor( SrcPtr[0].GetFloat(), SrcPtr[1].GetFloat(), 0.f,1.f);
SrcPtr += 2;
++DestPtr;
}
}
return true;
}
else if (Format == PF_G32R32F)
{
// not doing MinMax/Unorm remap here
// Read the data out of the buffer, converting it to FLinearColor.
for (uint32 Y = 0; Y < Height; Y++)
{
float * SrcPtr = (float *)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FLinearColor( SrcPtr[0], SrcPtr[1], 0.f, 1.f );
SrcPtr += 2;
++DestPtr;
}
}
return true;
}
else if (Format == PF_R32_FLOAT)
{
// not doing MinMax/Unorm remap here
// Read the data out of the buffer, converting it to FLinearColor.
for (uint32 Y = 0; Y < Height; Y++)
{
float * SrcPtr = (float *)(In + Y * SrcPitch);
FLinearColor* DestPtr = Out + Y * Width;
for (uint32 X = 0; X < Width; X++)
{
*DestPtr = FLinearColor( SrcPtr[0], 0.f, 0.f, 1.f );
++SrcPtr;
++DestPtr;
}
}
return true;
}
else
{
// not supported yet
check(0);
return false;
}
}
bool ConvertRAWSurfaceDataToFColor(EPixelFormat Format, uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out, FReadSurfaceDataFlags InFlags)
{
bool bLinearToGamma = InFlags.GetLinearToGamma();
if (Format == PF_G16 || Format == PF_R16_UINT)
{
ConvertRawR16DataToFColor(Width, Height, In, SrcPitch, Out);
return true;
}
else if (Format == PF_R8G8B8A8)
{
ConvertRawR8G8B8A8DataToFColor(Width, Height, In, SrcPitch, Out);
return true;
}
else if (Format == PF_B8G8R8A8)
{
ConvertRawB8G8R8A8DataToFColor(Width, Height, In, SrcPitch, Out);
return true;
}
else if (Format == PF_A2B10G10R10)
{
ConvertRawR10G10B10A2DataToFColor(Width, Height, In, SrcPitch, Out);
return true;
}
else if (Format == PF_FloatRGBA)
{
ConvertRawR16G16B16A16FDataToFColor(Width, Height, In, SrcPitch, Out, bLinearToGamma);
return true;
}
else if (Format == PF_FloatRGB || Format == PF_FloatR11G11B10)
{
ConvertRawR11G11B10DataToFColor(Width, Height, In, SrcPitch, Out, bLinearToGamma);
return true;
}
else if (Format == PF_A32B32G32R32F)
{
ConvertRawR32G32B32A32DataToFColor(Width, Height, In, SrcPitch, Out, bLinearToGamma);
return true;
}
else if (Format == PF_D24 || ((Format == PF_X24_G8 || Format == PF_DepthStencil) && GPixelFormats[Format].BlockBytes == 4))
{
ConvertRawR24G8DataToFColor(Width, Height, In, SrcPitch, Out, InFlags);
return true;
}
else if (Format == PF_A16B16G16R16)
{
ConvertRawR16G16B16A16DataToFColor(Width, Height, In, SrcPitch, Out);
return true;
}
else if (Format == PF_G16R16)
{
ConvertRawR16G16DataToFColor(Width, Height, In, SrcPitch, Out);
return true;
}
else
{
// not supported yet
check(0);
return false;
}
}
#if defined(DXGI_FORMAT_DEFINED) && DXGI_FORMAT_DEFINED
// switching on platform format
// could switch on EPixelFormat instead and make this more generic
// have to be a little careful with that as the mapping is not one to one
/** Convert D3D format type to general pixel format type*/
bool ConvertDXGIToFColor(DXGI_FORMAT Format, uint32 Width, uint32 Height, uint8 *In, uint32 SrcPitch, FColor* Out, FReadSurfaceDataFlags InFlags)
{
// todo : use a helper to map all the typeless to unorm before switching here ; see DXGIUtilities
bool bLinearToGamma = InFlags.GetLinearToGamma();
switch (Format)
{
case DXGI_FORMAT_R16_TYPELESS:
case DXGI_FORMAT_R16_UNORM:
ConvertRawR16DataToFColor(Width, Height, In, SrcPitch, Out);
return true;
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
ConvertRawR8G8B8A8DataToFColor(Width, Height, In, SrcPitch, Out);
return true;
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
ConvertRawB8G8R8A8DataToFColor(Width, Height, In, SrcPitch, Out);
return true;
case DXGI_FORMAT_R10G10B10A2_UNORM:
ConvertRawR10G10B10A2DataToFColor(Width, Height, In, SrcPitch, Out);
return true;
case DXGI_FORMAT_R16G16B16A16_FLOAT:
ConvertRawR16G16B16A16FDataToFColor(Width, Height, In, SrcPitch, Out, bLinearToGamma);
return true;
case DXGI_FORMAT_R11G11B10_FLOAT:
ConvertRawR11G11B10DataToFColor(Width, Height, In, SrcPitch, Out, bLinearToGamma);
return true;
case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
ConvertRawR9G9B9E5DataToFColor(Width, Height, In, SrcPitch, Out, bLinearToGamma);
return true;
case DXGI_FORMAT_R32G32B32A32_FLOAT:
ConvertRawR32G32B32A32DataToFColor(Width, Height, In, SrcPitch, Out, bLinearToGamma);
return true;
case DXGI_FORMAT_R24G8_TYPELESS:
ConvertRawR24G8DataToFColor(Width, Height, In, SrcPitch, Out, InFlags);
return true;
case DXGI_FORMAT_R32G8X24_TYPELESS:
ConvertRawDepthStencil64DataToFColor(Width, Height, In, SrcPitch, Out, InFlags);
return true;
case DXGI_FORMAT_R16G16B16A16_UNORM:
ConvertRawR16G16B16A16DataToFColor(Width, Height, In, SrcPitch, Out, bLinearToGamma);
return true;
case DXGI_FORMAT_R16G16_UNORM:
ConvertRawR16G16DataToFColor(Width, Height, In, SrcPitch, Out);
return true;
case DXGI_FORMAT_R8_UNORM:
ConvertRawR8DataToFColor(Width, Height, In, SrcPitch, Out);
return true;
case DXGI_FORMAT_R8G8_UNORM:
ConvertRawR8G8DataToFColor(Width, Height, In, SrcPitch, Out);
return true;
default:
return false;
}
}
#endif // DXGI_FORMAT_DEFINED
}; // namespace