Files
UnrealEngine/Engine/Plugins/Mutable/Source/MutableRuntime/Public/MuR/ImageDataStorage.h
2025-05-18 13:04:45 +08:00

212 lines
6.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "MuR/ImageTypes.h"
#include "MuR/MemoryTrackingAllocationPolicy.h"
#include "Containers/Array.h"
#include "Containers/ArrayView.h"
#include "Containers/StaticArray.h"
#include <atomic>
#define UE_API MUTABLERUNTIME_API
namespace mu::MemoryCounters
{
struct FImageMemoryCounter
{
static UE_API std::atomic<SSIZE_T>& Get();
};
}
namespace mu
{
using FImageArray = TArray<uint8, FDefaultMemoryTrackingAllocator<MemoryCounters::FImageMemoryCounter>>;
}
namespace mu::FImageDataStorageInternal
{
FORCEINLINE int32 ComputeNumLODsForSize(FImageSize Size)
{
return static_cast<int32>(FMath::CeilLogTwo(FMath::Max(Size.X, Size.Y))) + 1;
}
}
namespace mu
{
class FImageDataStorage
{
public:
TArray<FImageArray, TInlineAllocator<1>> Buffers;
FImageSize ImageSize = FImageSize(0, 0);
EImageFormat ImageFormat = EImageFormat::None;
uint8 NumLODs = 0;
static constexpr int32 NumLODsInCompactedTail = 7;
// This is needed for images its size cannot be known from dimensions and format, e.g., RLE compressed formats.
// It stores the offset to the end of the LOD so that CompactedTailOffsets[LOD] - CompactedTailOffsets[LOD - 1]
// is the size of LOD.
TStaticArray<uint16, NumLODsInCompactedTail> CompactedTailOffsets = MakeUniformStaticArray<uint16, NumLODsInCompactedTail>(0);
public:
MUTABLERUNTIME_API FImageDataStorage();
MUTABLERUNTIME_API FImageDataStorage(const FImageDesc& Desc);
MUTABLERUNTIME_API FImageDataStorage(const FImageDataStorage& Other);
MUTABLERUNTIME_API FImageDataStorage& operator=(const FImageDataStorage& Other);
FImageDataStorage(FImageDataStorage&& Other) = default;
FImageDataStorage& operator=(FImageDataStorage&& Other) = default;
MUTABLERUNTIME_API bool operator==(const FImageDataStorage& Other) const;
FORCEINLINE FImageDesc MakeImageDesc() const
{
return FImageDesc(ImageSize, ImageFormat, NumLODs);
}
FORCEINLINE void InitVoid(const FImageDesc& Desc)
{
Buffers.Empty();
CompactedTailOffsets[0] = TNumericLimits<uint16>::Max();
ImageSize = Desc.m_size;
ImageFormat = Desc.m_format;
NumLODs = Desc.m_lods;
}
FORCEINLINE bool IsVoid() const
{
return Buffers.IsEmpty() && CompactedTailOffsets[0] == TNumericLimits<uint16>::Max();
}
MUTABLERUNTIME_API void InitInternalArray(int32 Index, int32 Size, EInitializationType InitType);
MUTABLERUNTIME_API void Init(const FImageDesc& ImageDesc, EInitializationType InitType);
MUTABLERUNTIME_API void CopyFrom(const FImageDataStorage& Other);
FORCEINLINE int32 GetNumLODs() const
{
return NumLODs;
}
/**
* Get a const view to the data containing the LODIndex.
*/
MUTABLERUNTIME_API TArrayView<const uint8> GetLOD(int32 LODIndex) const;
/**
* Get a view to the data containing the LODIndex.
*/
MUTABLERUNTIME_API TArrayView<uint8> GetLOD(int32 LODIndex);
/**
* Change the number of lods in the image. If InNumLODs is smaller than the current lod count,
* LODs are dropped from the tail up.
*/
MUTABLERUNTIME_API void SetNumLODs(int32 InNumLODs, EInitializationType InitType = EInitializationType::NotInitialized);
/**
* Remove NumLODsToDrop starting form LOD 0. The resulting image will be smaller.
*/
MUTABLERUNTIME_API void DropLODs(int32 NumLODsToDrop);
/**
* Resizes LODIndex Data to NewSizeBytes
*/
MUTABLERUNTIME_API void ResizeLOD(int32 LODIndex, int32 NewSizeBytes);
FORCEINLINE const FImageArray& GetInternalArray(int32 LODIndex) const
{
check(!IsVoid());
check(LODIndex < NumLODs);
return Buffers[FMath::Min(LODIndex, ComputeFirstCompactedTailLOD())];
}
FORCEINLINE FImageArray& GetInternalArray(int32 LODIndex)
{
check(!IsVoid());
check(LODIndex < NumLODs);
return Buffers[FMath::Min(LODIndex, ComputeFirstCompactedTailLOD())];
}
FORCEINLINE int32 ComputeFirstCompactedTailLOD() const
{
using namespace FImageDataStorageInternal;
return FMath::Max(0, ComputeNumLODsForSize(ImageSize) - NumLODsInCompactedTail);
}
/**
* Stateless iteration in batches.
*/
MUTABLERUNTIME_API int32 GetNumBatches(int32 BatchSizeInElems, int32 BatchElemSizeInBytes) const;
MUTABLERUNTIME_API TArrayView<const uint8> GetBatch(int32 BatchId, int32 BatchSizeInElems, int32 BatchElemSizeInBytes) const;
MUTABLERUNTIME_API TArrayView<uint8> GetBatch(int32 BatchId, int32 BatchSizeInElems, int32 BatchElemSizeInBytes);
/**
* Returns the number of batches GetBatchFirtsLODOffet will admit and that will cover
* the first LOD buffer with OffsetInBytes removed from the front.
*
* A batch cannot be larger than BatchElemsSize. The last batch of a buffer will be smaller if
* BatchSizeInElems*BatchElemSizeInBytes is not multiple of the buffer size.
*
**/
MUTABLERUNTIME_API int32 GetNumBatchesFirstLODOffset(int32 BatchSizeInElems, int32 BatchElemSizeInBytes, int32 OffsetInBytes) const;
/**
* Returns a non modifiable view to the portion of the first LOD buffer with OffsetInBytes for the BatchId
*
* A batch cannot be larger than BatchElemsSize. The last batch of a buffer will be smaller if
* BatchSizeInElems*BatchElemSizeInBytes is not multiple of the buffer size.
*
*/
MUTABLERUNTIME_API TArrayView<const uint8> GetBatchFirstLODOffset(int32 BatchId, int32 BatchSizeInElems, int32 BatchElemSizeInBytes, int32 OffsetInBytes) const;
/**
* Non const version of GetBatchFirstLODOffset().
*/
MUTABLERUNTIME_API TArrayView<uint8> GetBatchFirstLODOffset(int32 BatchId, int32 BatchSizeInElems, int32 BatchElemSizeInBytes, int32 OffsetInBytes = 0);
/**
* Returns the number of batches GetBatchLODRange will admit and that will cover
* the [LODBegin, LODEnd) range.
*
**/
MUTABLERUNTIME_API int32 GetNumBatchesLODRange(int32 BatchSizeInElems, int32 BatchElemSizeInBytes, int32 LODBegin, int32 LODEnd) const;
/**
* Returns a non modifiable view to the portion of the [LODBegin, LODEnd) for the BatchId.
*
* A batch cannot be larger than BatchElemsSize. The last batch of a buffer will be smaller if
* BatchSizeInElems*BatchElemSizeInBytes is not multiple of the buffer size.
*
*/
MUTABLERUNTIME_API TArrayView<const uint8> GetBatchLODRange(int32 BatchId, int32 BatchSizeInElems, int32 BatchElemSizeInBytes, int32 LODBegin, int32 LODEnd) const;
/**
* Non const version of GetBatchLODRange().
*/
MUTABLERUNTIME_API TArrayView<uint8> GetBatchLODRange(int32 BatchId, int32 BatchSizeInElems, int32 BatchElemSizeInBytes, int32 LODBegin, int32 LODEnd);
MUTABLERUNTIME_API int32 GetAllocatedSize() const;
MUTABLERUNTIME_API int32 GetDataSize() const;
/**
* Returns true if all buffers are empty. This can be true after initialization for image formats that report
* BytesPerBlock 0, e.g., RLE formats. If not initialized will also return true.
*/
MUTABLERUNTIME_API bool IsEmpty() const;
MUTABLERUNTIME_API void Serialise(FOutputArchive& Arch) const;
MUTABLERUNTIME_API void Unserialise(FInputArchive& Arch);
};
}
#undef UE_API