From cdcf8defd03dbabbbd2d9538ed81eae068faf08a Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Thu, 20 Jan 2022 13:53:51 -0600 Subject: [PATCH] Added special case support for R8_SNORM, R16_SNORM, and R16_FLOAT Signed-off-by: Chris Galvan --- .../RPI.Reflect/Image/StreamingImageAsset.cpp | 103 +++++++++++++++++- 1 file changed, 100 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/StreamingImageAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/StreamingImageAsset.cpp index 099f9c3df9..aaf232d4f0 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/StreamingImageAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/StreamingImageAsset.cpp @@ -15,6 +15,84 @@ namespace AZ { namespace Internal { + // The original implementation was from cryhalf's CryConvertFloatToHalf and CryConvertHalfToFloat function + // Will be replaced with centralized half float API + struct SHalf + { + explicit SHalf(float floatValue) + { + AZ::u32 Result; + + AZ::u32 intValue = ((AZ::u32*)(&floatValue))[0]; + AZ::u32 Sign = (intValue & 0x80000000U) >> 16U; + intValue = intValue & 0x7FFFFFFFU; + + if (intValue > 0x47FFEFFFU) + { + // The number is too large to be represented as a half. Saturate to infinity. + Result = 0x7FFFU; + } + else + { + if (intValue < 0x38800000U) + { + // The number is too small to be represented as a normalized half. + // Convert it to a denormalized value. + AZ::u32 Shift = 113U - (intValue >> 23U); + intValue = (0x800000U | (intValue & 0x7FFFFFU)) >> Shift; + } + else + { + // Rebias the exponent to represent the value as a normalized half. + intValue += 0xC8000000U; + } + + Result = ((intValue + 0x0FFFU + ((intValue >> 13U) & 1U)) >> 13U) & 0x7FFFU; + } + h = static_cast(Result | Sign); + } + + operator float() const + { + AZ::u32 Mantissa; + AZ::u32 Exponent; + AZ::u32 Result; + + Mantissa = h & 0x03FF; + + if ((h & 0x7C00) != 0) // The value is normalized + { + Exponent = ((h >> 10) & 0x1F); + } + else if (Mantissa != 0) // The value is denormalized + { + // Normalize the value in the resulting float + Exponent = 1; + + do + { + Exponent--; + Mantissa <<= 1; + } while ((Mantissa & 0x0400) == 0); + + Mantissa &= 0x03FF; + } + else // The value is zero + { + Exponent = static_cast(-112); + } + + Result = ((h & 0x8000) << 16) | // Sign + ((Exponent + 112) << 23) | // Exponent + (Mantissa << 13); // Mantissa + + return *(float*)&Result; + } + + private: + AZ::u16 h; + }; + template float RetrieveFloatValue(const AZ::u8* mem, size_t index) { @@ -51,23 +129,42 @@ namespace AZ return 0; } + float ScaleValue(float value, float origMin, float origMax, float scaledMin, float scaledMax) + { + return ((value - origMin) / (origMax - origMin)) * (scaledMax - scaledMin) + scaledMin; + } + float RetrieveFloatValue(const AZ::u8* mem, size_t index, AZ::RHI::Format format) { switch (format) { case AZ::RHI::Format::R8_UNORM: - case AZ::RHI::Format::R8_SNORM: case AZ::RHI::Format::A8_UNORM: { return mem[index] / static_cast(std::numeric_limits::max()); } - case AZ::RHI::Format::R16_FLOAT: + case AZ::RHI::Format::R8_SNORM: + { + // Scale the value from AZ::s8 min/max to -1 to 1 + auto actualMem = reinterpret_cast(mem); + return ScaleValue(actualMem[index], std::numeric_limits::min(), std::numeric_limits::max(), -1, 1); + } case AZ::RHI::Format::D16_UNORM: case AZ::RHI::Format::R16_UNORM: - case AZ::RHI::Format::R16_SNORM: { return mem[index] / static_cast(std::numeric_limits::max()); } + case AZ::RHI::Format::R16_SNORM: + { + // Scale the value from AZ::s16 min/max to -1 to 1 + auto actualMem = reinterpret_cast(mem); + return ScaleValue(actualMem[index], std::numeric_limits::min(), std::numeric_limits::max(), -1, 1); + } + case AZ::RHI::Format::R16_FLOAT: + { + auto actualMem = reinterpret_cast(mem); + return SHalf(actualMem[index]); + } case AZ::RHI::Format::D32_FLOAT: case AZ::RHI::Format::R32_FLOAT: {