// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include #include #include #include typedef uint64 HashType; typedef std::vector HashTypeVec; typedef std::list HashTypeList; class CHash; typedef std::shared_ptr CHashPtr; typedef std::weak_ptr CHashPtrW; typedef std::vector CHashPtrVec; typedef std::vector CHashPtrWVec; //struct HashType //{ // uint64 HashValue; /// The actual HashValue Value //}; DECLARE_LOG_CATEGORY_EXTERN(LogData, Log, All); #define MX_HASH_VAL(HashValue, Prime, val) ((HashValue * Prime) ^ (val)) #define MX_HASH_VAL_DEF(val) MX_HASH_VAL(DataUtil::GFNVInit, DataUtil::GFNVPrime, (HashType)val) struct TEXTUREGRAPHENGINE_API DataUtil { static constexpr HashType GNullHash = 0; /// 0xDeadBeef; ////////////////////////////////////////////////////////////////////////// /// Hashing related ////////////////////////////////////////////////////////////////////////// static constexpr HashType GFNVPrime = 0x00000100000001B3; static const HashType GFNVInit = 0xcbf29ce484222325; /// Don't change this ... EVER! static const size_t GMaxChunk = 16 * 1024; /// Calculate HashValue for one chunk of data static HashType Hash(const uint8* data, size_t Length, HashType InitialHash = GFNVInit, HashType Prime = GFNVPrime); static HashType Hash_GenericString_Name(const FString& Name, HashType InitialHash = GFNVInit, HashType Prime = GFNVPrime); static HashType Hash(const HashTypeVec& SubHashes, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime); static HashType Hash(const CHashPtrVec& InSubHashes, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime); /// Automatically decide whether to chunk the HashValue or not static HashType Hash_One(const uint8* Data, size_t Length, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime); static HashType Hash_Chunked(const uint8* data, size_t Length, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime); static size_t GetOptimalHashingSize(size_t Size); template static HashType Hash_Simple(const T& Value, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime) { HashType H = 0; check(sizeof(Value) <= sizeof(HashType)); memcpy(&H, &Value, sizeof(T)); return MX_HASH_VAL(InitialValue, Prime, H); } ////////////////////////////////////////////////////////////////////////// /// Specialised versions ////////////////////////////////////////////////////////////////////////// static HashType Hash_Simple(const FString& Value, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime) { return Hash_GenericString_Name(Value, InitialValue, Prime); } static HashType Hash_Float(float Value, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime) { return Hash_Simple(Value, InitialValue, Prime); } static HashType Hash_Int32(int32 Value, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime) { return Hash_Simple(Value, InitialValue, Prime); } static HashType Hash_Double(double Value, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime) { return Hash_Simple(Value, InitialValue, Prime); } static HashType Hash_Bool(bool Value, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime) { return Hash_Simple(Value, InitialValue, Prime); } static HashType Hash_Simple(const FVector2D& Vec, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime) { HashType HashValue = InitialValue; HashValue = Hash_Float(Vec.X, HashValue, Prime); HashValue = Hash_Float(Vec.Y, HashValue, Prime); return HashValue; } static HashType Hash_Simple(const FVector& Vec, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime) { HashType HashValue = InitialValue; HashValue = Hash_Float(Vec.X, HashValue, Prime); HashValue = Hash_Float(Vec.Y, HashValue, Prime); HashValue = Hash_Float(Vec.Z, HashValue, Prime); return HashValue; } static HashType Hash_Simple(const FColor& Color, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime) { return Hash_Int32((int32)Color.DWColor()); } static HashType Hash_Simple(const FLinearColor& Color, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime) { HashType HashValue = InitialValue; HashValue = Hash_Float(Color.R, HashValue, Prime); HashValue = Hash_Float(Color.G, HashValue, Prime); HashValue = Hash_Float(Color.B, HashValue, Prime); HashValue = Hash_Float(Color.A, HashValue, Prime); return HashValue; } template static HashType Hash_Simple(const TMap& Map, HashType InitialValue = GFNVInit, HashType Prime = GFNVPrime) { HashTypeVec HashValues(Map.Num() * 2); size_t i = 0; for (auto& Iter : Map) { const TKey& key = Iter.Key; const TValue& Value = Iter.Value; HashValues[i++] = Hash_Simple(key); HashValues[i++] = Hash_Simple(Value); } return DataUtil::Hash(HashValues, InitialValue, Prime); } }; ////////////////////////////////////////////////////////////////////////// /// Hash data structure ////////////////////////////////////////////////////////////////////////// class TEXTUREGRAPHENGINE_API CHash : public std::enable_shared_from_this { private: HashType HashValue = DataUtil::GNullHash;/// The actual Value of the hash CHashPtrVec HashSources; /// The sources used to construct this hash bool bIsFinal = false; /// Whether this is a final (immutable hash) CHashPtr TempHashValue; /// Whether there's a temporary HashValue attached with this HashValue FDateTime Timestamp = FDateTime::Now(); /// The timestamp of when this was last updated /// This structure represents a HashValue link. This is required for cases when a temp HashValue is used in /// the calculation of some other complex HashValue. When the temp HashValue finally resolves, we need to /// update the linked HashValues so that our look-ups to the, now old embedded HashValues is successful. /// otherwise we'll have no way of connecting complex-temp hashes to the correct hash and /// determine whether a job has already been done before or not CHashPtrWVec Linked; /// The HashValues that have this HashValue embedded in it. This is kept /// temporarily if THIS HASH is a temp HashValue. When THIS HASH gets /// updated, we can update the linked parent HashValues HashTypeVec IntermediateHashes; /// Intermediate hashes that might have been evaluated before this /// hash became finalised FORCEINLINE bool HasTempDependency_Internal() const { return (IsTemp() && !HashSources.empty() && TempHashValue->IsTemp()); } void AddLink(CHashPtrW Link); void CheckLinkCycles(std::unordered_set& Chain); void UpdateLinks(); void HandleLinkUpdated(CHashPtr LinkUpdated); /// DO NOT MAKE THIS C'TOR PUBLIC. Use ConstructFromSources instead explicit CHash(const CHashPtrVec& Sources); public: CHash(HashType Value, bool bInIsFinal); explicit CHash(CHashPtr Temp); bool TryFinalise(HashType FinalHash = DataUtil::GNullHash, bool UpdateBlobber = true); bool operator == (const CHash& RHS) const; HashTypeVec GetIntermediateHashes() const; static CHashPtr ConstructFromSources(const CHashPtrVec& Sources); static CHashPtr UpdateHash(CHashPtr NewHash, CHashPtr PrevHash); ////////////////////////////////////////////////////////////////////////// /// Inline functions ////////////////////////////////////////////////////////////////////////// FORCEINLINE bool IsNull() const { HashType CurrentHashValue = Value(); return CurrentHashValue == DataUtil::GNullHash || CurrentHashValue == 0; } FORCEINLINE bool IsValid() const { return !IsNull(); } FORCEINLINE HashType Value() const { return !TempHashValue ? HashValue : TempHashValue->HashValue; } FORCEINLINE operator HashType() const { return Value(); } FORCEINLINE bool IsFinal() const { return bIsFinal; } FORCEINLINE const FDateTime& GetTimestamp() const { return Timestamp; } FORCEINLINE bool HasUpdatedSince(FDateTime timestamp) const { return timestamp > Timestamp; } FORCEINLINE bool IsTemp() const { return TempHashValue != nullptr; } FORCEINLINE CHashPtr Temp() const { return TempHashValue; } FORCEINLINE bool HasTempDependency() const { return (IsTemp() && TempHashValue->HasTempDependency_Internal()) || (!IsTemp() && HasTempDependency_Internal()); } FORCEINLINE const CHashPtrVec& Sources() const { return !IsTemp() ? HashSources : TempHashValue->HashSources; } FORCEINLINE size_t NumSources() const { return !IsTemp() ? HashSources.size() : TempHashValue->HashSources.size(); } FORCEINLINE bool IsTempFinal() const { return IsFinal() && IsTemp(); } }; THIRD_PARTY_INCLUDES_START #include "continuable/continuable.hpp" THIRD_PARTY_INCLUDES_END typedef cti::continuable AscynCHashPtr; ////////////////////////////////////////////////////////////////////////// template class TEXTUREGRAPHENGINE_API T_Tiles { public: typedef std::vector TypeVec; protected: TypeVec TilesVec; /// The tiles size_t NumRows = 0; /// Number of rows size_t NumCols = 0; /// Number of columns public: T_Tiles() = default; T_Tiles(size_t InNumRows, size_t InNumCols) : NumRows(InNumRows), NumCols(InNumCols) { if (NumRows > 0 && NumCols > 0) TilesVec.resize(NumRows * NumCols); } T_Tiles(const TypeVec& RHS, size_t InNumRows, size_t InNumCols) : TilesVec(RHS) , NumRows(InNumRows) , NumCols(InNumCols) { } void Resize(size_t InNumRows, size_t InNumCols) { NumRows = InNumRows; NumCols = InNumCols; if (NumRows > 0 && NumCols > 0) TilesVec.resize(NumRows * NumCols); } FORCEINLINE size_t Length() const { return NumRows * NumCols; } template FORCEINLINE void ForEach(Functor Func) const { for (size_t RowId = 0; RowId < NumRows; ++RowId) { for (size_t ColId = 0; ColId < NumCols; ++ColId) { Func(RowId, ColId); } } } ////////////////////////////////////////////////////////////////////////// /// Inline functions ////////////////////////////////////////////////////////////////////////// FORCEINLINE const Type* operator[](size_t RowId) const { check(RowId < NumRows); return (TilesVec.data() + (RowId * NumCols)); } FORCEINLINE Type* operator[](size_t RowId) { check(RowId < NumRows); return (TilesVec.data() + (RowId * NumCols)); } FORCEINLINE const Type& operator()(size_t RowId, size_t ColId) const { check(RowId < NumRows && ColId < NumCols); return TilesVec[RowId * NumCols + ColId]; } FORCEINLINE Type& operator()(size_t RowId, size_t ColId) { check(RowId < NumRows && ColId < NumCols); return TilesVec[RowId * NumCols + ColId]; } FORCEINLINE size_t Rows() const { return NumRows; } FORCEINLINE size_t Cols() const { return NumCols; } FORCEINLINE const TypeVec& Tiles() const { return TilesVec; } FORCEINLINE TypeVec& Tiles() { return TilesVec; } FORCEINLINE void Clear() { TilesVec.clear(); } }; using TileInvalidateMatrix = T_Tiles;