2021-04-08 14:32:07 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
/*****************
|
|
|
|
|
*
|
|
|
|
|
* Oodle Data compression plugin
|
|
|
|
|
* provides Oodle compression for Pak files & iostore
|
|
|
|
|
* is not for generic compression usage
|
|
|
|
|
*
|
|
|
|
|
* The Oodle LZ codecs are extremely fast to decode and almost always speed up load times
|
|
|
|
|
*
|
|
|
|
|
* The codecs are :
|
|
|
|
|
* Kraken : high compression with good decode speed, the usual default
|
|
|
|
|
* Mermaid : less compression and faster decode speed; good when CPU bound or on platforms with less CPU power
|
|
|
|
|
* Selkie : even less compression and faster that Mermaid
|
|
|
|
|
* Leviathan : more compression and slower to decode than Kraken
|
|
|
|
|
*
|
|
|
|
|
* The encode time is mostly independent of the codec. Use the codec to choose decode speed, and the encoder effort
|
|
|
|
|
* level to control encode time.
|
|
|
|
|
*
|
|
|
|
|
* For daily iteration you might want level 3 ("Fast"). For shipping packages you might want level 6 ("optimal2") or higher.
|
|
|
|
|
* The valid level range is -4 to 9
|
|
|
|
|
*
|
|
|
|
|
* This plugin reads its options on the command line via "compressmethod" and "compresslevel"
|
|
|
|
|
* eg. "-compressmethod=Kraken -compresslevel=4"
|
|
|
|
|
*
|
|
|
|
|
* The Oodle decoder can decode any codec used, it doesn't need to know which one was used.
|
|
|
|
|
*
|
|
|
|
|
* Compression options should be set up in your Game.ini ; for example :
|
|
|
|
|
*
|
|
|
|
|
|
|
|
|
|
[/Script/UnrealEd.ProjectPackagingSettings]
|
|
|
|
|
bCompressed=True
|
|
|
|
|
bForceUseProjectCompressionFormat=False
|
2021-04-20 10:14:26 -04:00
|
|
|
PackageCompressionFormat=Oodle
|
2021-05-19 12:14:25 -04:00
|
|
|
PackageAdditionalCompressionOptions=-compressionblocksize=256KB
|
|
|
|
|
PackageCompressionMethod=Kraken
|
|
|
|
|
PackageCompressionLevel_Distribution=7
|
2021-04-20 10:14:26 -04:00
|
|
|
PackageCompressionLevel_TestShipping=5
|
2021-05-19 12:14:25 -04:00
|
|
|
PackageCompressionLevel_DebugDevelopment=4
|
2021-04-08 14:32:07 -04:00
|
|
|
|
|
|
|
|
* This can be set in DefaultGame.ini then overrides set up per-platform.
|
|
|
|
|
*
|
|
|
|
|
* The Engine also has a veto compressionformat set up in the DataDrivenPlatformInfo.ini for each platform in the field
|
|
|
|
|
* "HardwareCompressionFormat"
|
|
|
|
|
* eg. platforms that don't want any software compressor can set "HardwareCompressionFormat=None" and this will override what you
|
2021-04-20 10:14:26 -04:00
|
|
|
* set in "PackageCompressionFormat".
|
2021-04-08 14:32:07 -04:00
|
|
|
*
|
2021-04-20 10:14:26 -04:00
|
|
|
* The idea is in typical use, you set "PackageCompressionFormat" for your Game, and you get that compressor on most platforms, but on
|
2021-04-08 14:32:07 -04:00
|
|
|
* some platforms that don't want compression, it automatically turns off.
|
|
|
|
|
*
|
|
|
|
|
* If you want to force use of your Game.ini compressor (ignore the HardwareCompressionFormat) you can set bForceUseProjectCompressionFormat
|
|
|
|
|
* in ProjectPackagingSettings.
|
|
|
|
|
*
|
|
|
|
|
*
|
2021-04-20 10:14:26 -04:00
|
|
|
* When using Oodle we recommend "-compressionblocksize=1MB -asynccompression" which can be set with PackageAdditionalCompressionOptions.
|
2021-04-08 14:32:07 -04:00
|
|
|
*
|
|
|
|
|
* ***************************/
|
|
|
|
|
|
|
|
|
|
#include "CoreMinimal.h"
|
|
|
|
|
#include "CoreTypes.h"
|
|
|
|
|
#include "Misc/Compression.h"
|
|
|
|
|
#include "Misc/ICompressionFormat.h"
|
|
|
|
|
#include "Misc/CommandLine.h"
|
2021-06-11 17:34:39 -04:00
|
|
|
#include "Misc/ConfigCacheIni.h"
|
2021-04-08 14:32:07 -04:00
|
|
|
#include "Misc/Parse.h"
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
#include "Settings/ProjectPackagingSettings.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-04-29 19:32:06 -04:00
|
|
|
#include "OodleDataCompressionFormatPCH.h"
|
2021-04-08 14:32:07 -04:00
|
|
|
|
2021-04-29 19:32:06 -04:00
|
|
|
DEFINE_LOG_CATEGORY_STATIC(OodleDataCompression, Log, All);
|
2021-04-08 14:32:07 -04:00
|
|
|
|
|
|
|
|
#define OODLE_DERIVEDDATA_VER TEXT("BA7AA26CD1C3498787A3F3AA53895042")
|
|
|
|
|
|
2021-04-29 19:32:06 -04:00
|
|
|
// if the Decoder object is <= this size, just put it on the stack
|
|
|
|
|
// MAX_OODLE_DECODER_SIZE_ON_STACK needs to be at least 64k to ever be used
|
|
|
|
|
// the benefit of this could be more parallel decodes if the 2 pre-allocated buffers are in use
|
|
|
|
|
// without resorting to a heap alloc
|
|
|
|
|
#define MAX_OODLE_DECODER_SIZE_ON_STACK 0
|
|
|
|
|
// if you can guarantee this much stack available :
|
|
|
|
|
//#define MAX_OODLE_DECODER_SIZE_ON_STACK 100000
|
|
|
|
|
|
2021-04-08 14:32:07 -04:00
|
|
|
|
|
|
|
|
|
2021-04-29 19:32:06 -04:00
|
|
|
struct FOodleDataCompressionFormat : ICompressionFormat
|
2021-04-08 14:32:07 -04:00
|
|
|
{
|
|
|
|
|
OodleLZ_Compressor Compressor;
|
|
|
|
|
OodleLZ_CompressionLevel CompressionLevel;
|
|
|
|
|
OodleLZ_CompressOptions CompressionOptions;
|
2021-04-29 19:32:06 -04:00
|
|
|
int32 OodleDecoderMemorySize;
|
2021-06-11 17:34:39 -04:00
|
|
|
int32 OodleDecoderBufferCount =0;
|
2021-04-08 14:32:07 -04:00
|
|
|
|
2021-06-11 17:34:39 -04:00
|
|
|
FCriticalSection* OodleDecoderMutexes =0;
|
|
|
|
|
void ** OodleDecoderMemory =0;
|
2021-04-08 14:32:07 -04:00
|
|
|
|
2021-04-29 19:32:06 -04:00
|
|
|
FOodleDataCompressionFormat(OodleLZ_Compressor InCompressor, OodleLZ_CompressionLevel InCompressionLevel, int InSpaceSpeedTradeoffBytes)
|
2021-04-08 14:32:07 -04:00
|
|
|
{
|
|
|
|
|
Compressor = InCompressor;
|
|
|
|
|
CompressionLevel = InCompressionLevel;
|
|
|
|
|
CompressionOptions = *OodleLZ_CompressOptions_GetDefault(Compressor, CompressionLevel);
|
|
|
|
|
CompressionOptions.spaceSpeedTradeoffBytes = InSpaceSpeedTradeoffBytes;
|
|
|
|
|
// we're usually doing limited chunks, no need for LRM :
|
|
|
|
|
CompressionOptions.makeLongRangeMatcher = false;
|
|
|
|
|
|
|
|
|
|
// enough decoder scratch for any compressor & buffer size.
|
|
|
|
|
// note "InCompressor" is what we want to Encode with but we may be asked to decode other compressors!
|
2021-06-11 17:34:39 -04:00
|
|
|
OodleDecoderMemorySize = (int32) OodleLZDecoder_MemorySizeNeeded(OodleLZ_Compressor_Invalid, -1);
|
2021-04-08 14:32:07 -04:00
|
|
|
|
2021-06-11 17:34:39 -04:00
|
|
|
int32 BufferCount = 2;
|
|
|
|
|
GConfig->GetInt(TEXT("OodleDataCompressionFormat"), TEXT("PreallocatedBufferCount"), BufferCount, GEngineIni);
|
|
|
|
|
if (BufferCount < 0)
|
2021-04-08 14:32:07 -04:00
|
|
|
{
|
2021-06-11 17:34:39 -04:00
|
|
|
BufferCount = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OodleDecoderBufferCount = BufferCount;
|
|
|
|
|
if (OodleDecoderBufferCount)
|
|
|
|
|
{
|
|
|
|
|
OodleDecoderMutexes = new FCriticalSection[OodleDecoderBufferCount];
|
|
|
|
|
OodleDecoderMemory = new void* [OodleDecoderBufferCount];
|
|
|
|
|
FMemory::Memzero(OodleDecoderMemory, sizeof(void*) * OodleDecoderBufferCount);
|
2021-04-08 14:32:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-29 19:32:06 -04:00
|
|
|
virtual ~FOodleDataCompressionFormat()
|
2021-06-11 17:34:39 -04:00
|
|
|
{
|
|
|
|
|
if (OodleDecoderBufferCount)
|
2021-04-08 14:32:07 -04:00
|
|
|
{
|
2021-06-11 17:34:39 -04:00
|
|
|
for (int i = 0; i < OodleDecoderBufferCount; ++i)
|
2021-04-08 14:32:07 -04:00
|
|
|
{
|
2021-06-11 17:34:39 -04:00
|
|
|
if (OodleDecoderMutexes[i].TryLock())
|
2021-04-08 14:32:07 -04:00
|
|
|
{
|
|
|
|
|
FMemory::Free(OodleDecoderMemory[i]);
|
|
|
|
|
OodleDecoderMemory[i] = 0;
|
2021-06-11 17:34:39 -04:00
|
|
|
OodleDecoderMutexes[i].Unlock();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(OodleDataCompression, Error, TEXT("FOodleDataCompressionFormat - shutting down while in use?"));
|
2021-04-08 14:32:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
2021-06-11 17:34:39 -04:00
|
|
|
|
|
|
|
|
delete [] OodleDecoderMutexes;
|
|
|
|
|
delete [] OodleDecoderMemory;
|
2021-04-08 14:32:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FString GetCompressorString() const
|
|
|
|
|
{
|
|
|
|
|
// convert values to enums
|
|
|
|
|
switch (Compressor)
|
|
|
|
|
{
|
|
|
|
|
case OodleLZ_Compressor_Selkie: return TEXT("Selkie");
|
|
|
|
|
case OodleLZ_Compressor_Mermaid: return TEXT("Mermaid");
|
|
|
|
|
case OodleLZ_Compressor_Kraken: return TEXT("Kraken");
|
|
|
|
|
case OodleLZ_Compressor_Leviathan: return TEXT("Leviathan");
|
|
|
|
|
case OodleLZ_Compressor_Hydra: return TEXT("Hydra");
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
return TEXT("Unknown");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FString GetCompressionLevelString() const
|
|
|
|
|
{
|
|
|
|
|
switch (CompressionLevel)
|
|
|
|
|
{
|
|
|
|
|
case OodleLZ_CompressionLevel_HyperFast4: return TEXT("HyperFast4");
|
|
|
|
|
case OodleLZ_CompressionLevel_HyperFast3: return TEXT("HyperFast3");
|
|
|
|
|
case OodleLZ_CompressionLevel_HyperFast2: return TEXT("HyperFast2");
|
|
|
|
|
case OodleLZ_CompressionLevel_HyperFast1: return TEXT("HyperFast1");
|
|
|
|
|
case OodleLZ_CompressionLevel_None: return TEXT("None");
|
|
|
|
|
case OodleLZ_CompressionLevel_SuperFast: return TEXT("SuperFast");
|
|
|
|
|
case OodleLZ_CompressionLevel_VeryFast: return TEXT("VeryFast");
|
|
|
|
|
case OodleLZ_CompressionLevel_Fast: return TEXT("Fast");
|
|
|
|
|
case OodleLZ_CompressionLevel_Normal: return TEXT("Normal");
|
|
|
|
|
case OodleLZ_CompressionLevel_Optimal1: return TEXT("Optimal1");
|
|
|
|
|
case OodleLZ_CompressionLevel_Optimal2: return TEXT("Optimal2");
|
|
|
|
|
case OodleLZ_CompressionLevel_Optimal3: return TEXT("Optimal3");
|
|
|
|
|
case OodleLZ_CompressionLevel_Optimal4: return TEXT("Optimal4");
|
|
|
|
|
case OodleLZ_CompressionLevel_Optimal5: return TEXT("Optimal5");
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
return TEXT("Unknown");
|
|
|
|
|
}
|
2021-05-09 12:47:12 -04:00
|
|
|
|
|
|
|
|
virtual bool DoesOwnWorthDecompressingCheck() override
|
|
|
|
|
{
|
|
|
|
|
// Oodle does own "worth it" check internally, don't add one
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-04-08 14:32:07 -04:00
|
|
|
|
|
|
|
|
virtual FName GetCompressionFormatName() override
|
|
|
|
|
{
|
2021-04-29 19:32:06 -04:00
|
|
|
static FName OodleName( TEXT("Oodle") );
|
|
|
|
|
return OodleName;
|
2021-04-08 14:32:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual uint32 GetVersion() override
|
|
|
|
|
{
|
|
|
|
|
return 20000 + OODLE2_VERSION_MAJOR*100 + OODLE2_VERSION_MINOR;
|
|
|
|
|
}
|
2021-04-29 19:32:06 -04:00
|
|
|
|
2021-04-08 14:32:07 -04:00
|
|
|
int32 OodleDecode(const void * InCompBuf, int32 InCompBufSize, void * OutRawBuf, int32 InRawLen)
|
|
|
|
|
{
|
2021-04-29 19:32:06 -04:00
|
|
|
// find the minimum size needed for this decode, OodleDecoderMemorySize may be larger
|
2021-04-08 14:32:07 -04:00
|
|
|
OodleLZ_Compressor CurCompressor = OodleLZ_GetChunkCompressor(InCompBuf, InCompBufSize, NULL);
|
|
|
|
|
SSIZE_T DecoderMemorySize = OodleLZDecoder_MemorySizeNeeded(CurCompressor, InRawLen);
|
2021-04-29 19:32:06 -04:00
|
|
|
void * DecoderMemory = NULL;
|
|
|
|
|
bool DoFreeDecoderMemory = false;
|
|
|
|
|
|
|
|
|
|
#if MAX_OODLE_DECODER_SIZE_ON_STACK > 0
|
|
|
|
|
if ( DecoderMemorySize <= MAX_OODLE_DECODER_SIZE_ON_STACK )
|
2021-04-08 14:32:07 -04:00
|
|
|
{
|
2021-04-29 19:32:06 -04:00
|
|
|
// InRawLen is small
|
|
|
|
|
// just use the stack for our needed decoded memory scrtach
|
|
|
|
|
|
|
|
|
|
DecoderMemory = alloca(DecoderMemorySize);
|
|
|
|
|
|
|
|
|
|
//UE_LOG(OodleDataCompression, Display, TEXT("Decode on stack : %d -> %d"),InCompBufSize,InRawLen );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// try to take a mutex for one of the pre-allocated decode buffers
|
2021-06-11 17:34:39 -04:00
|
|
|
for (int i = 0; i < OodleDecoderBufferCount; ++i)
|
2021-04-29 19:32:06 -04:00
|
|
|
{
|
2021-06-11 17:34:39 -04:00
|
|
|
if (OodleDecoderMutexes[i].TryLock())
|
2021-04-29 19:32:06 -04:00
|
|
|
{
|
2021-06-11 17:34:39 -04:00
|
|
|
if (OodleDecoderMemory[i] == nullptr)
|
|
|
|
|
{
|
|
|
|
|
// Haven't allocated yet (we allocate on demand)
|
|
|
|
|
OodleDecoderMemory[i] = FMemory::Malloc(OodleDecoderMemorySize);
|
|
|
|
|
if (OodleDecoderMemory[i] == nullptr)
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(OodleDataCompression, Error, TEXT("FOodleDataCompressionFormat - Failed to allocate preallocated buffer %d bytes!"), OodleDecoderMemorySize);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-29 19:32:06 -04:00
|
|
|
if (OodleDecoderMemory[i])
|
|
|
|
|
{
|
|
|
|
|
//UE_LOG(OodleDataCompression, Display, TEXT("Decode with lock : %d -> %d"),InCompBufSize,InRawLen );
|
|
|
|
|
|
|
|
|
|
int Result = OodleLZ_Decompress(InCompBuf, InCompBufSize, OutRawBuf, InRawLen,
|
|
|
|
|
OodleLZ_FuzzSafe_Yes, OodleLZ_CheckCRC_Yes, OodleLZ_Verbosity_None,
|
|
|
|
|
NULL, 0, NULL, NULL,
|
|
|
|
|
OodleDecoderMemory[i], OodleDecoderMemorySize);
|
|
|
|
|
|
2021-06-11 17:34:39 -04:00
|
|
|
OodleDecoderMutexes[i].Unlock();
|
2021-04-29 19:32:06 -04:00
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-11 17:34:39 -04:00
|
|
|
OodleDecoderMutexes[i].Unlock();
|
2021-04-29 19:32:06 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//UE_LOG(OodleDataCompression, Display, TEXT("Decode with malloc : %d -> %d"),InCompBufSize,InRawLen );
|
|
|
|
|
|
|
|
|
|
// allocate memory for the decoder so that Oodle doesn't allocate anything internally
|
|
|
|
|
DecoderMemory = FMemory::Malloc(DecoderMemorySize);
|
|
|
|
|
if (DecoderMemory == NULL)
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(OodleDataCompression, Error, TEXT("FOodleDataCompressionFormat::OodleDecode - Failed to allocate %d!"), DecoderMemorySize);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
DoFreeDecoderMemory = true;
|
2021-04-08 14:32:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Result = OodleLZ_Decompress(InCompBuf, InCompBufSize, OutRawBuf, InRawLen,
|
|
|
|
|
OodleLZ_FuzzSafe_Yes,OodleLZ_CheckCRC_Yes,OodleLZ_Verbosity_None,
|
|
|
|
|
NULL, 0, NULL, NULL,
|
|
|
|
|
DecoderMemory, DecoderMemorySize);
|
|
|
|
|
|
2021-04-29 19:32:06 -04:00
|
|
|
if ( DoFreeDecoderMemory )
|
|
|
|
|
{
|
|
|
|
|
FMemory::Free(DecoderMemory);
|
|
|
|
|
}
|
2021-04-08 14:32:07 -04:00
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual FString GetDDCKeySuffix() override
|
|
|
|
|
{
|
|
|
|
|
// DerivedDataCache key string
|
|
|
|
|
// ideally this should be unique for any settings changed
|
|
|
|
|
return FString::Printf(TEXT("C_%s_CL_%s_%s"), *GetCompressorString(), *GetCompressionLevelString(), OODLE_DERIVEDDATA_VER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool Compress(void* OutCompressedBuffer, int32& OutCompressedSize, const void* InUncompressedBuffer, int32 InUncompressedSize, int32 InCompressionData) override
|
|
|
|
|
{
|
|
|
|
|
// OutCompressedSize is read-write
|
|
|
|
|
int32 CompressedBufferSize = OutCompressedSize;
|
|
|
|
|
|
|
|
|
|
// CompressedSize should be >= GetCompressedBufferSize(UncompressedSize, CompressionData)
|
|
|
|
|
check(CompressedBufferSize >= GetCompressedBufferSize(InUncompressedSize, InCompressionData));
|
|
|
|
|
|
|
|
|
|
OO_SINTa Result = OodleLZ_Compress(Compressor, InUncompressedBuffer, InUncompressedSize, OutCompressedBuffer, CompressionLevel, &CompressionOptions);
|
|
|
|
|
|
|
|
|
|
// verbose log all compresses :
|
2021-04-29 19:32:06 -04:00
|
|
|
//UE_LOG(OodleDataCompression, Display, TEXT("Oodle Compress : %d -> %d"), UncompressedSize, Result);
|
2021-04-08 14:32:07 -04:00
|
|
|
|
|
|
|
|
if (Result <= 0)
|
|
|
|
|
{
|
|
|
|
|
OutCompressedSize = -1;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OutCompressedSize = (int32) Result;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool Uncompress(void* OutUncompressedBuffer, int32& OutUncompressedSize, const void* InCompressedBuffer, int32 InCompressedSize, int32 CompressionData) override
|
|
|
|
|
{
|
|
|
|
|
// OutUncompressedSize is read-write
|
|
|
|
|
int32 UncompressedSize = OutUncompressedSize;
|
|
|
|
|
int Result = OodleDecode(InCompressedBuffer, InCompressedSize, OutUncompressedBuffer, UncompressedSize);
|
|
|
|
|
if (Result > 0)
|
|
|
|
|
{
|
|
|
|
|
// Result should == UncompressedSize
|
|
|
|
|
check(Result == UncompressedSize);
|
|
|
|
|
OutUncompressedSize = Result;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual int32 GetCompressedBufferSize(int32 UncompressedSize, int32 CompressionData) override
|
|
|
|
|
{
|
|
|
|
|
// CompressionData is not used
|
|
|
|
|
int32 Needed = (int32)OodleLZ_GetCompressedBufferSizeNeeded(Compressor, UncompressedSize);
|
|
|
|
|
return Needed;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2021-04-29 19:32:06 -04:00
|
|
|
class FOodleDataCompressionFormatModuleInterface : public IModuleInterface
|
2021-04-08 14:32:07 -04:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
virtual void StartupModule() override
|
|
|
|
|
{
|
|
|
|
|
// settings to use in non-tools context (eg. runtime game encoding) :
|
|
|
|
|
// (SetDefaultOodleOptionsForPackaging sets options for pak compression & iostore)
|
2021-05-13 09:27:25 -04:00
|
|
|
OodleLZ_Compressor UsedCompressor = OodleLZ_Compressor_Mermaid;
|
2021-04-08 14:32:07 -04:00
|
|
|
OodleLZ_CompressionLevel UsedLevel = OodleLZ_CompressionLevel_Fast;
|
|
|
|
|
int32 SpaceSpeedTradeoff = 0;
|
|
|
|
|
|
2021-05-13 09:27:25 -04:00
|
|
|
#if ( (!UE_BUILD_SHIPPING) || WITH_EDITOR )
|
2021-04-08 14:32:07 -04:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// parse the command line to get compressor & level settings
|
|
|
|
|
|
|
|
|
|
// this Startup is done in various different contexts;
|
|
|
|
|
// when the editor loads up
|
|
|
|
|
// when the game loads (we will be used to decompress only and encode settings are not used)
|
|
|
|
|
// when the package cooking tool loads up <- this is when we set the relevant encode settings
|
|
|
|
|
|
|
|
|
|
// is_program is true for cooker & UnrealPak (not Editor or Game)
|
|
|
|
|
bool IsProgram = IS_PROGRAM;
|
|
|
|
|
|
|
|
|
|
bool IsCommandlet = IsRunningCommandlet();
|
|
|
|
|
bool IsIOStore = IsCommandlet && FCString::Strifind(FCommandLine::Get(), TEXT("-run=iostore")) != NULL;
|
|
|
|
|
|
|
|
|
|
// we only need to be doing all this when run as UnrealPak or iostore commandlet
|
|
|
|
|
// (IsProgram also picks up cooker and a few other things, that's okay)
|
|
|
|
|
if ( IsIOStore || IsProgram )
|
|
|
|
|
{
|
|
|
|
|
// defaults if no options set :
|
|
|
|
|
UsedCompressor = OodleLZ_Compressor_Kraken;
|
|
|
|
|
// Kraken is a good compromise of compression ratio & speed
|
|
|
|
|
|
|
|
|
|
UsedLevel = OodleLZ_CompressionLevel_Normal;
|
|
|
|
|
// for faster iteration time during development
|
|
|
|
|
|
|
|
|
|
SpaceSpeedTradeoff = 0; // 0 means use default
|
|
|
|
|
// SpaceSpeedTradeoff is mainly for tuning the Hydra compressor
|
|
|
|
|
// it can also be used to skew your compression towards higher ratio vs faster decode
|
|
|
|
|
|
|
|
|
|
// convert values to enums
|
|
|
|
|
TMap<FString, OodleLZ_Compressor> MethodMap =
|
|
|
|
|
{
|
|
|
|
|
{ TEXT("Selkie"), OodleLZ_Compressor_Selkie },
|
|
|
|
|
{ TEXT("Mermaid"), OodleLZ_Compressor_Mermaid },
|
|
|
|
|
{ TEXT("Kraken"), OodleLZ_Compressor_Kraken },
|
|
|
|
|
{ TEXT("Leviathan"), OodleLZ_Compressor_Leviathan },
|
|
|
|
|
{ TEXT("Hydra"), OodleLZ_Compressor_Hydra },
|
2021-04-29 19:32:06 -04:00
|
|
|
// when adding here remember to update FOodleDataCompressionFormat::GetCompressorString()
|
2021-04-08 14:32:07 -04:00
|
|
|
};
|
|
|
|
|
TMap<FString, OodleLZ_CompressionLevel> LevelMap =
|
|
|
|
|
{
|
|
|
|
|
{ TEXT("HyperFast4"), OodleLZ_CompressionLevel_HyperFast4 },
|
|
|
|
|
{ TEXT("HyperFast3"), OodleLZ_CompressionLevel_HyperFast3 },
|
|
|
|
|
{ TEXT("HyperFast2"), OodleLZ_CompressionLevel_HyperFast2 },
|
|
|
|
|
{ TEXT("HyperFast1"), OodleLZ_CompressionLevel_HyperFast1 },
|
|
|
|
|
{ TEXT("HyperFast"), OodleLZ_CompressionLevel_HyperFast1 },
|
|
|
|
|
{ TEXT("None") , OodleLZ_CompressionLevel_None },
|
|
|
|
|
{ TEXT("SuperFast"), OodleLZ_CompressionLevel_SuperFast },
|
|
|
|
|
{ TEXT("VeryFast"), OodleLZ_CompressionLevel_VeryFast },
|
|
|
|
|
{ TEXT("Fast") , OodleLZ_CompressionLevel_Fast },
|
|
|
|
|
{ TEXT("Normal"), OodleLZ_CompressionLevel_Normal },
|
|
|
|
|
{ TEXT("Optimal1"), OodleLZ_CompressionLevel_Optimal1 },
|
|
|
|
|
{ TEXT("Optimal2"), OodleLZ_CompressionLevel_Optimal2 },
|
|
|
|
|
{ TEXT("Optimal") , OodleLZ_CompressionLevel_Optimal2 },
|
|
|
|
|
{ TEXT("Optimal3"), OodleLZ_CompressionLevel_Optimal3 },
|
|
|
|
|
{ TEXT("Optimal4"), OodleLZ_CompressionLevel_Optimal4 },
|
|
|
|
|
{ TEXT("Optimal5"), OodleLZ_CompressionLevel_Optimal5 },
|
|
|
|
|
|
|
|
|
|
{ TEXT("-4"), OodleLZ_CompressionLevel_HyperFast4 },
|
|
|
|
|
{ TEXT("-3"), OodleLZ_CompressionLevel_HyperFast3 },
|
|
|
|
|
{ TEXT("-2"), OodleLZ_CompressionLevel_HyperFast2 },
|
|
|
|
|
{ TEXT("-1"), OodleLZ_CompressionLevel_HyperFast1 },
|
|
|
|
|
{ TEXT("0"), OodleLZ_CompressionLevel_None },
|
|
|
|
|
{ TEXT("1"), OodleLZ_CompressionLevel_SuperFast },
|
|
|
|
|
{ TEXT("2"), OodleLZ_CompressionLevel_VeryFast },
|
|
|
|
|
{ TEXT("3"), OodleLZ_CompressionLevel_Fast },
|
|
|
|
|
{ TEXT("4"), OodleLZ_CompressionLevel_Normal },
|
|
|
|
|
{ TEXT("5"), OodleLZ_CompressionLevel_Optimal1 },
|
|
|
|
|
{ TEXT("6"), OodleLZ_CompressionLevel_Optimal2 },
|
|
|
|
|
{ TEXT("7"), OodleLZ_CompressionLevel_Optimal3 },
|
|
|
|
|
{ TEXT("8"), OodleLZ_CompressionLevel_Optimal4 },
|
|
|
|
|
{ TEXT("9"), OodleLZ_CompressionLevel_Optimal5 },
|
2021-04-29 19:32:06 -04:00
|
|
|
// when adding here remember to update FOodleDataCompressionFormat::GetCompressionLevelString()
|
2021-04-08 14:32:07 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// override from command line :
|
|
|
|
|
FString Method = "";
|
|
|
|
|
FString Level = "";
|
|
|
|
|
|
|
|
|
|
// let commandline override
|
|
|
|
|
//FParse::Value does not change output fields if they are not found
|
|
|
|
|
FParse::Value(FCommandLine::Get(), TEXT("compressmethod="), Method);
|
|
|
|
|
FParse::Value(FCommandLine::Get(), TEXT("compresslevel="), Level);
|
|
|
|
|
FParse::Value(FCommandLine::Get(), TEXT("OodleSpaceSpeedTradeoff="), SpaceSpeedTradeoff);
|
|
|
|
|
|
|
|
|
|
OodleLZ_Compressor * pUsedCompressor = MethodMap.Find(Method);
|
|
|
|
|
OodleLZ_CompressionLevel * pUsedLevel = LevelMap.Find(Level);
|
|
|
|
|
|
|
|
|
|
if (pUsedCompressor) UsedCompressor = *pUsedCompressor;
|
|
|
|
|
if (pUsedLevel) UsedLevel = *pUsedLevel;
|
|
|
|
|
|
|
|
|
|
// no init log line if we're not enabled :
|
|
|
|
|
bool bUseCompressionFormatOodle = FCString::Strifind(FCommandLine::Get(), TEXT("-compressionformats=oodle")) != NULL;
|
|
|
|
|
if ( bUseCompressionFormatOodle )
|
|
|
|
|
{
|
2021-04-29 19:32:06 -04:00
|
|
|
UE_LOG(OodleDataCompression, Display, TEXT("Oodle v%s initializing with method=%s, level=%d=%s"), TEXT(OodleVersion), **MethodMap.FindKey(UsedCompressor), (int)UsedLevel, **LevelMap.FindKey(UsedLevel) );
|
2021-04-08 14:32:07 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endif // SHIPPING
|
|
|
|
|
|
|
|
|
|
//-----------------------------------
|
|
|
|
|
// register the compression format :
|
|
|
|
|
// this is used by the shipping game to decode any paks compressed with Oodle :
|
|
|
|
|
|
2021-04-29 19:32:06 -04:00
|
|
|
CompressionFormat = new FOodleDataCompressionFormat(UsedCompressor, UsedLevel, SpaceSpeedTradeoff);
|
2021-04-08 14:32:07 -04:00
|
|
|
|
|
|
|
|
IModularFeatures::Get().RegisterModularFeature(COMPRESSION_FORMAT_FEATURE_NAME, CompressionFormat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void ShutdownModule() override
|
|
|
|
|
{
|
|
|
|
|
IModularFeatures::Get().UnregisterModularFeature(COMPRESSION_FORMAT_FEATURE_NAME, CompressionFormat);
|
|
|
|
|
delete CompressionFormat;
|
|
|
|
|
CompressionFormat = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ICompressionFormat* CompressionFormat = nullptr;
|
|
|
|
|
};
|
|
|
|
|
|
2021-04-29 19:32:06 -04:00
|
|
|
IMPLEMENT_MODULE(FOodleDataCompressionFormatModuleInterface, OodleDataCompressionFormat);
|