Files
UnrealEngineUWP/Engine/Source/Developer/TextureFormat/Private/TextureFormatManagerModule.cpp
charles bloom be238dee17 fix failures on texture import of rare cases
fix RHI upload of textures that are multiple of 4 in top mip but not in lower mips
dont pad CompressedImage sizes, store true size
clean up Texture size limits and VT conditions
better default settings for texture import
clean up initialization order of TextureFormatManagerModule

#preflight 6250814a11261bc7b23d8f4b
#rb fabian.giesen,julien.stjean

[CL 19693287 by charles bloom in ue5-main branch]
2022-04-08 16:06:54 -04:00

249 lines
7.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "CoreMinimal.h"
#include "Interfaces/ITextureFormatManagerModule.h"
#include "Interfaces/ITextureFormat.h"
#include "Interfaces/ITextureFormatModule.h"
#include "Modules/ModuleManager.h"
#include "TextureFormatManager.h"
DEFINE_LOG_CATEGORY_STATIC(LogTextureFormatManager, Log, All);
/**
* Module for the target platform manager
*/
class FTextureFormatManagerModule
: public ITextureFormatManagerModule
{
public:
enum class EInitPhase
{
JustConstructedNotInit = 0,
Invalidated = 1,
GetTextureFormatsInProgressDontTouch = 2,
GetTextureFormatsPartialOkayToRead = 3, // values >= here are okay to make queries
GetTextureFormatsDone = 4
};
/** Default constructor. */
FTextureFormatManagerModule()
: ModuleName(TEXT("TextureFormat"))
, bForceCacheUpdate(true)
, bModuleChangeCallbackEnabled(false)
, TextureFormatsInitPhase(EInitPhase::JustConstructedNotInit)
{
FModuleManager::Get().OnModulesChanged().AddRaw(this, &FTextureFormatManagerModule::ModulesChangesCallback);
// not usable until first Invalidate is called
}
/** Destructor. */
virtual ~FTextureFormatManagerModule() = default;
virtual void ShutdownModule()
{
FModuleManager::Get().OnModulesChanged().RemoveAll(this);
}
virtual const TArray<const ITextureFormat*>& GetTextureFormats() override
{
// should not be called recursively while I am building the list :
check( TextureFormatsInitPhase!= EInitPhase::GetTextureFormatsInProgressDontTouch );
// bForceCacheUpdate should be true on first call, so we don't need a separate static init flag
if ( bForceCacheUpdate )
{
// turn off flag immediately so that repeated calls to GetTextureFormats will not come in here again
bForceCacheUpdate = false;
bModuleChangeCallbackEnabled = false; // don't re-call me from my own module loads
TextureFormatsInitPhase = EInitPhase::GetTextureFormatsInProgressDontTouch;
// note the first time this is done is from FTargetPlatformManagerModule::FTargetPlatformManagerModule()
// so calls to it are dangerous
TextureFormats.Empty(TextureFormats.Num());
TextureFormatMetadata.Empty(TextureFormatMetadata.Num());
TArray<FName> Modules;
FModuleManager::Get().FindModules(TEXT("*TextureFormat*"), Modules);
if (!Modules.Num())
{
UE_LOG(LogTextureFormatManager, Error, TEXT("No texture formats found!"));
}
TArray<FTextureFormatMetadata> BaseModules;
TArray<FTextureFormatMetadata> ChildModules;
for (int32 Index = 0; Index < Modules.Num(); Index++)
{
if (Modules[Index] != ModuleName) // Avoid our own module when going through this list that was gathered by name
{
ITextureFormatModule* Module = FModuleManager::LoadModulePtr<ITextureFormatModule>(Modules[Index]);
if (Module)
{
FTextureFormatMetadata ModuleMeta;
ModuleMeta.Module = Module;
ModuleMeta.ModuleName = Modules[Index];
if ( Module->CanCallGetTextureFormats() )
{
ChildModules.Add(ModuleMeta);
}
else
{
BaseModules.Add(ModuleMeta);
}
}
}
}
// first populate TextureFormats[] with all Base Modules
//
for (int32 Index = 0; Index < BaseModules.Num(); Index++)
{
ITextureFormatModule* Module = BaseModules[Index].Module;
ITextureFormat* Format = Module->GetTextureFormat();
if (Format != nullptr)
{
UE_LOG(LogTextureFormatManager, Display, TEXT("Loaded Base TextureFormat: %s"),*BaseModules[Index].ModuleName.ToString());
TextureFormats.Add(Format);
TextureFormatMetadata.Add(BaseModules[Index]);
}
}
// Init phase 3 means you are now allowd to call GetTextureFormats() and you will get only the Base formats
TextureFormatsInitPhase = EInitPhase::GetTextureFormatsPartialOkayToRead;
// run through the Child formats and call GetTextureFormat() on them
// this will call back to me and do GetTextureFormats() which will get only the base formats
for (int32 Index = 0; Index < ChildModules.Num(); Index++)
{
ITextureFormatModule* Module = ChildModules[Index].Module;
ITextureFormat* Format = Module->GetTextureFormat();
if (Format != nullptr)
{
UE_LOG(LogTextureFormatManager, Display, TEXT("Loaded Child TextureFormat: %s"),*ChildModules[Index].ModuleName.ToString());
// do not add me to TextureFormats yet
}
}
// back up phase to 2, no calls to GetTextureFormats() allowed now
TextureFormatsInitPhase = EInitPhase::GetTextureFormatsInProgressDontTouch;
for (int32 Index = 0; Index < ChildModules.Num(); Index++)
{
ITextureFormatModule* Module = ChildModules[Index].Module;
// GetTextureFormat was already done so this should just return a stored pointer, no more init
ITextureFormat* Format = Module->GetTextureFormat();
if (Format != nullptr)
{
// now add to the list :
TextureFormats.Add(Format);
TextureFormatMetadata.Add(ChildModules[Index]);
}
}
// all done :
TextureFormatsInitPhase = EInitPhase::GetTextureFormatsDone;
bModuleChangeCallbackEnabled = true;
}
check( (int)TextureFormatsInitPhase >= (int)EInitPhase::GetTextureFormatsPartialOkayToRead );
return TextureFormats;
}
virtual const ITextureFormat* FindTextureFormat(FName Name) override
{
check( (int)TextureFormatsInitPhase >= (int)EInitPhase::GetTextureFormatsPartialOkayToRead );
FName ModuleNameUnused;
ITextureFormatModule* ModuleUnused;
return FindTextureFormatAndModule(Name, ModuleNameUnused, ModuleUnused);
}
virtual const class ITextureFormat* FindTextureFormatAndModule(FName Name, FName& OutModuleName, ITextureFormatModule*& OutModule) override
{
check( (int)TextureFormatsInitPhase >= (int)EInitPhase::GetTextureFormatsPartialOkayToRead );
// Called to ensure the arrays are populated
// dangerous and not necessary, removed :
check( ! bForceCacheUpdate );
//GetTextureFormats();
for (int32 Index = 0; Index < TextureFormats.Num(); Index++)
{
TArray<FName> Formats;
TextureFormats[Index]->GetSupportedFormats(Formats);
for (int32 FormatIndex = 0; FormatIndex < Formats.Num(); FormatIndex++)
{
if (Formats[FormatIndex] == Name)
{
const FTextureFormatMetadata& FoundMeta = TextureFormatMetadata[Index];
OutModuleName = FoundMeta.ModuleName;
OutModule = FoundMeta.Module;
return TextureFormats[Index];
}
}
}
return nullptr;
}
virtual void Invalidate() override
{
// this is called right after the constructor
// we are not usable until the first Invalidate is called
TextureFormatsInitPhase = EInitPhase::Invalidated;
bForceCacheUpdate = true;
GetTextureFormats();
}
private:
void ModulesChangesCallback(FName InModuleName, EModuleChangeReason ReasonForChange)
{
if (bModuleChangeCallbackEnabled && (InModuleName != ModuleName) && InModuleName.ToString().Contains(TEXT("TextureFormat")))
{
// when a "TextureFormat" module is loaded, rebuild my list
Invalidate();
}
}
FName ModuleName;
TArray<const ITextureFormat*> TextureFormats;
struct FTextureFormatMetadata
{
FName ModuleName;
ITextureFormatModule* Module;
};
TArray<FTextureFormatMetadata> TextureFormatMetadata;
// Flag to force reinitialization of all cached data. This is needed to have up-to-date caches
// in case of a module reload of a TextureFormat-Module.
bool bForceCacheUpdate;
// Flag to avoid redunant reloads
bool bModuleChangeCallbackEnabled;
// Track tricky initialization progress
EInitPhase TextureFormatsInitPhase;
// @@!! Mutex and ScopeLock everything in case this is called from multiple threads ?
};
IMPLEMENT_MODULE(FTextureFormatManagerModule, TextureFormat);