Files
UnrealEngineUWP/Engine/Source/Developer/TextureBuildUtilities/Private/TextureBuildUtilities.cpp
dan thompson 6083992f93 Switch to xxhash for mip hashing.
#rb fabian.giesen
#jira UE-183751
#preflight 645d2b79ea1c7ba4d6b744d7

[CL 25438535 by dan thompson in ue5-main branch]
2023-05-11 19:32:41 -04:00

278 lines
9.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "TextureBuildUtilities.h"
#include "TextureCompressorModule.h" // for FTextureBuildSettings
#include "Misc/DataDrivenPlatformInfoRegistry.h"
#include "Serialization/CompactBinary.h"
#include "Serialization/CompactBinaryWriter.h"
//#include "EngineLogs.h" // can't use from SCW
namespace UE
{
namespace TextureBuildUtilities
{
// Return true if texture format name is HDR
TEXTUREBUILDUTILITIES_API bool TextureFormatIsHdr(FName const& InName)
{
// TextureFormatRemovePrefixFromName first !
static FName NameRGBA16F(TEXT("RGBA16F"));
static FName NameRGBA32F(TEXT("RGBA32F"));
static FName NameR16F(TEXT("R16F"));
static FName NameR32F(TEXT("R32F"));
static FName NameBC6H(TEXT("BC6H"));
if ( InName == NameRGBA16F ) return true;
if ( InName == NameRGBA32F ) return true;
if ( InName == NameR16F ) return true;
if ( InName == NameR32F ) return true;
if ( InName == NameBC6H ) return true;
return false;
}
TEXTUREBUILDUTILITIES_API const FName TextureFormatRemovePlatformPrefixFromName(FName const& InName)
{
FString NameString = InName.ToString();
// Format names may have one of the following forms:
// - PLATFORM_PREFIX_FORMAT
// - PLATFORM_FORMAT
// - PREFIX_FORMAT
// - FORMAT
// We have to remove the platform prefix first, if it exists.
// Then we detect a non-platform prefix (such as codec name)
// and split the result into explicit FORMAT and PREFIX parts.
// fast(ish) early out if there are no underscores in InName :
int32 UnderscoreIndexIgnored = INDEX_NONE;
if ( ! NameString.FindChar(TCHAR('_'), UnderscoreIndexIgnored))
{
return InName;
}
for (FName PlatformName : FDataDrivenPlatformInfoRegistry::GetSortedPlatformNames(EPlatformInfoType::AllPlatformInfos))
{
FString PlatformTextureFormatPrefix = PlatformName.ToString();
PlatformTextureFormatPrefix += TEXT('_');
if (NameString.StartsWith(PlatformTextureFormatPrefix, ESearchCase::IgnoreCase))
{
// Remove platform prefix and proceed with non-platform prefix detection.
FString PlatformRemoved = NameString.RightChop(PlatformTextureFormatPrefix.Len());
return FName( PlatformRemoved );
}
}
return InName;
}
TEXTUREBUILDUTILITIES_API const FName TextureFormatRemovePrefixFromName(FName const& InNameWithPlatform, FName& OutPrefix)
{
// first remove platform prefix :
FName NameWithoutPlatform = TextureFormatRemovePlatformPrefixFromName( InNameWithPlatform );
FString NameString = NameWithoutPlatform.ToString();
// then see if there's another underscore separated prefix :
int32 UnderscoreIndex = INDEX_NONE;
if ( ! NameString.FindChar(TCHAR('_'), UnderscoreIndex))
{
return NameWithoutPlatform;
}
// texture format names can have underscores in them (eg. ETC2_RG11)
// so need to differentiate between that and a conditional prefix :
// found an underscore; is it a composite texture name, or an "Alternate" prefix?
FString Prefix = NameString.Left(UnderscoreIndex + 1);
if ( Prefix == "OODLE_" || Prefix == "TFO_" )
{
// Alternate prefix
OutPrefix = FName( Prefix );
return FName( NameString.RightChop(UnderscoreIndex + 1) );
}
else if ( Prefix == "ASTC_" || Prefix == "ETC2_" )
{
// composite format, don't split
return NameWithoutPlatform;
}
else
{
// prefix not recognized
// LogTexture doesn't exist in SCW
UE_LOG(LogCore,Warning,TEXT("Texture Format Prefix not recognized: %s [%s]"),*Prefix,*InNameWithPlatform.ToString());
return NameWithoutPlatform;
}
}
TEXTUREBUILDUTILITIES_API ERawImageFormat::Type GetVirtualTextureBuildIntermediateFormat(const FTextureBuildSettings& BuildSettings)
{
// Platform prefix should have already been removed, also remove any Oodle prefix:
const FName TextureFormatName = TextureFormatRemovePrefixFromName(BuildSettings.TextureFormatName);
// note: using RGBA16F when the Source is HDR but the output is not HDR is not needed
// you could use BGRA8 intermediate in that case
// but it's rare and not a big problem, so leave it alone for now
const bool bIsHdr = BuildSettings.bHDRSource || TextureFormatIsHdr(TextureFormatName);
if (bIsHdr)
{
return ERawImageFormat::RGBA16F;
}
else if ( TextureFormatName == "G16" )
{
return ERawImageFormat::G16;
}
else
{
return ERawImageFormat::BGRA8;
}
}
#ifndef TEXT_TO_ENUM
#define TEXT_TO_ENUM(eVal, txt) if (txt.Compare(#eVal) == 0) return eVal;
#endif
static EPixelFormat GetPixelFormatFromUtf8(const FUtf8StringView& InPixelFormatStr)
{
#define TEXT_TO_PIXELFORMAT(f) TEXT_TO_ENUM(f, InPixelFormatStr);
FOREACH_ENUM_EPIXELFORMAT(TEXT_TO_PIXELFORMAT)
#undef TEXT_TO_PIXELFORMAT
return PF_Unknown;
}
namespace EncodedTextureExtendedData
{
FCbObject ToCompactBinary(const FEncodedTextureExtendedData& InExtendedData)
{
FCbWriter Writer;
Writer.BeginObject();
Writer.AddInteger("NumMipsInTail", InExtendedData.NumMipsInTail);
Writer.AddInteger("ExtData", InExtendedData.ExtData);
Writer.BeginArray("MipSizes");
for (uint64 MipSize : InExtendedData.MipSizesInBytes)
{
Writer.AddInteger(MipSize);
}
Writer.EndArray();
Writer.EndObject();
return Writer.Save().AsObject();
}
bool FromCompactBinary(FEncodedTextureExtendedData& OutExtendedData, FCbObject InCbObject)
{
OutExtendedData.ExtData = InCbObject["ExtData"].AsUInt32();
OutExtendedData.NumMipsInTail = InCbObject["NumMipsInTail"].AsInt32();
FCbArrayView MipArrayView = InCbObject["MipSizes"].AsArrayView();
for (FCbFieldView MipFieldView : MipArrayView)
{
OutExtendedData.MipSizesInBytes.Add(MipFieldView.AsUInt64());
}
return true;
}
} // namespace EncodedTextureExtendedData
namespace EncodedTextureDescription
{
FCbObject ToCompactBinary(const FEncodedTextureDescription& InDescription)
{
FCbWriter Writer;
Writer.BeginObject();
Writer.AddInteger("TopMipSizeX", InDescription.TopMipSizeX);
Writer.AddInteger("TopMipSizeY", InDescription.TopMipSizeY);
Writer.AddInteger("TopMipVolumeSizeZ", InDescription.TopMipVolumeSizeZ);
Writer.AddInteger("ArraySlices", InDescription.ArraySlices);
Writer.AddString("PixelFormat", GetPixelFormatString(InDescription.PixelFormat));
Writer.AddInteger("NumMips", InDescription.NumMips);
Writer.AddBool("bCubeMap", InDescription.bCubeMap);
Writer.AddBool("bTextureArray", InDescription.bTextureArray);
Writer.AddBool("bVolumeTexture", InDescription.bVolumeTexture);
Writer.EndObject();
return Writer.Save().AsObject();
}
bool FromCompactBinary(FEncodedTextureDescription& OutDescription, FCbObject InCbObject)
{
OutDescription.TopMipSizeX = InCbObject["TopMipSizeX"].AsInt32();
OutDescription.TopMipSizeY = InCbObject["TopMipSizeY"].AsInt32();
OutDescription.TopMipVolumeSizeZ = InCbObject["TopMipVolumeSizeZ"].AsInt32();
OutDescription.ArraySlices = InCbObject["ArraySlices"].AsInt32();
OutDescription.PixelFormat = GetPixelFormatFromUtf8(InCbObject["PixelFormat"].AsString());
OutDescription.NumMips = (uint8)InCbObject["NumMips"].AsInt32();
OutDescription.bCubeMap = InCbObject["bCubeMap"].AsBool();
OutDescription.bTextureArray = InCbObject["bTextureArray"].AsBool();
OutDescription.bVolumeTexture = InCbObject["bVolumeTexture"].AsBool();
return true;
}
} // namespace EncodedTextureDescription
namespace TextureEngineParameters
{
FCbObject ToCompactBinaryWithDefaults(const FTextureEngineParameters& InEngineParameters)
{
FTextureEngineParameters Defaults;
FCbWriter Writer;
Writer.BeginObject();
if (InEngineParameters.bEngineSupportsTexture2DArrayStreaming != Defaults.bEngineSupportsTexture2DArrayStreaming)
{
Writer.AddBool("bEngineSupportsTexture2DArrayStreaming", InEngineParameters.bEngineSupportsTexture2DArrayStreaming);
}
if (InEngineParameters.bEngineSupportsVolumeTextureStreaming != Defaults.bEngineSupportsVolumeTextureStreaming)
{
Writer.AddBool("bEngineSupportsVolumeTextureStreaming", InEngineParameters.bEngineSupportsVolumeTextureStreaming);
}
if (InEngineParameters.NumInlineDerivedMips != Defaults.NumInlineDerivedMips)
{
Writer.AddInteger("NumInlineDerivedMips", InEngineParameters.NumInlineDerivedMips);
}
Writer.EndObject();
return Writer.Save().AsObject();
}
bool FromCompactBinary(FTextureEngineParameters& OutEngineParameters, FCbObject InCbObject)
{
OutEngineParameters = FTextureEngineParameters(); // init to defaults
OutEngineParameters.NumInlineDerivedMips = InCbObject["NumInlineDerivedMips"].AsInt32(OutEngineParameters.NumInlineDerivedMips);
OutEngineParameters.bEngineSupportsTexture2DArrayStreaming = InCbObject["bEngineSupportsTexture2DArrayStreaming"].AsBool(OutEngineParameters.bEngineSupportsTexture2DArrayStreaming);
OutEngineParameters.bEngineSupportsVolumeTextureStreaming = InCbObject["bEngineSupportsVolumeTextureStreaming"].AsBool(OutEngineParameters.bEngineSupportsVolumeTextureStreaming);
return true;
}
} // namespace EncodedTextureDescription
FCbObject FTextureBuildMetadata::ToCompactBinaryWithDefaults() const
{
FTextureBuildMetadata Defaults;
FCbWriter Writer;
Writer.BeginObject();
if (bSourceMipsAlphaDetected != Defaults.bSourceMipsAlphaDetected)
{
Writer.AddBool("bSourceMipsAlphaDetected", bSourceMipsAlphaDetected);
}
if (PreEncodeMipsHash != Defaults.PreEncodeMipsHash)
{
Writer << UTF8TEXTVIEW("PreEncodeMipsHash") << PreEncodeMipsHash;
}
Writer.EndObject();
return Writer.Save().AsObject();
}
FTextureBuildMetadata::FTextureBuildMetadata(FCbObject InCbObject)
{
bSourceMipsAlphaDetected = InCbObject["bSourceMipsAlphaDetected"].AsBool(bSourceMipsAlphaDetected);
PreEncodeMipsHash = InCbObject["PreEncodeMipsHash"].AsUInt64(PreEncodeMipsHash);
}
} // namespace
}