Files

197 lines
6.2 KiB
C++
Raw Permalink Normal View History

// Copyright Epic Games, Inc. All Rights Reserved.
#include "HAL/FileManager.h"
#include "HAL/IConsoleManager.h"
#include "Logging/LogMacros.h"
#include "Misc/PackageName.h"
#include "Misc/PackagePath.h"
#include "Misc/ScopedSlowTask.h"
#include "UObject/PackageFileSummary.h"
#include "UObject/PackageResourceManager.h"
#include "UObject/PackageTrailer.h"
#include "VirtualizationExperimentalUtilities.h"
#define LOCTEXT_NAMESPACE "Virtualization"
namespace UE
{
#if WITH_EDITORONLY_DATA
FString BytesToString(int64 SizeInBytes)
{
if (SizeInBytes < (8 *1024))
{
return FString::Printf(TEXT("%4" INT64_FMT " bytes"), SizeInBytes);
}
else if (SizeInBytes < (1024 * 1024))
{
double SizeInKb = static_cast<double>(SizeInBytes) / (1024.0);
return FString::Printf(TEXT("%.2f KB"), SizeInKb);
}
else
{
double SizeInMB = static_cast<double>(SizeInBytes) / (1024.0 * 1024.0);
return FString::Printf(TEXT("%.2f MB"), SizeInMB);
}
}
void LogPackageError(FArchive* Ar, const TCHAR* DebugName)
{
if (Ar == nullptr)
{
UE_LOG(LogVirtualization, Error, TEXT("Could not find the package file: '%s'"), DebugName);
return;
}
FPackageFileSummary Summary;
*Ar << Summary;
if (Ar->IsError())
{
UE_LOG(LogVirtualization, Error, TEXT("Could not find load the package summary from disk: '%s'"), DebugName);
return;
}
if (Summary.Tag != PACKAGE_FILE_TAG)
{
UE_LOG(LogVirtualization, Error, TEXT("Package summary seems to be corrupted: '%s'"), DebugName);
return;
}
int32 PackageVersion = Summary.GetFileVersionUE().ToValue();
if (PackageVersion >= (int32)EUnrealEngineObjectUE5Version::PAYLOAD_TOC)
{
UE_LOG(LogVirtualization, Error, TEXT("Package trailer is missing from the package file: '%s'"), DebugName);
return;
}
UE_LOG(LogVirtualization, Error, TEXT("Package is tool old (version %d) to have a package trailer (version %d): '%s'"), PackageVersion, int(EUnrealEngineObjectUE5Version::PAYLOAD_TOC), DebugName);
}
void LogPackageError(const FPackagePath& Path)
{
const FString DebugName = Path.GetPackageName();
TUniquePtr<FArchive> PackageAr = IPackageResourceManager::Get().OpenReadExternalResource(EPackageExternalResource::WorkspaceDomainFile, DebugName);
LogPackageError(PackageAr.Get(), *DebugName);
}
void LogPackageError(const FString& Path)
{
TUniquePtr<FArchive> PackageAr(IFileManager::Get().CreateFileReader(*Path));
LogPackageError(PackageAr.Get(), *Path);
}
/**
* This function is used to write information about package's payloads to the log file. This has no
* practical development use and should only be used for debugging purposes.
*
* @param Args The function expects each arg to be a valid package path. Failure to provide a valid
* package path will result in errors being written to the log.
*/
void DumpPackagePayloadInfo(const TArray<FString>& Args)
{
if (Args.Num() == 0)
{
UE_LOG(LogVirtualization, Error, TEXT("Command 'DumpPackagePayloadInfo' called without any arguments"));
return;
}
TRACE_CPUPROFILER_EVENT_SCOPE(DumpPackagePayloadInfo);
FScopedSlowTask Progress(0.0f, LOCTEXT("VAFindPayloadInfo", "Finding payload info..."));
for (const FString& Arg : Args)
{
FString PathString;
if (FPackageName::ParseExportTextPath(Arg, nullptr /*OutClassName*/, &PathString))
{
PathString = FPackageName::ObjectPathToPackageName(PathString);
}
else
{
PathString = Arg;
}
FPackageTrailer Trailer;
FPackagePath Path;
if (FPackagePath::TryFromMountedName(PathString, Path))
{
It is now possible to disable virtualization for all payloads owned by a specific asset type by adding the name of the asset to [Core.ContentVirtualization]DisabledAsset string array in the engine ini file. #rb Per.Larsson #rnx #jira UE-151377 #preflight 628364050039ea57a52d6989 ### Virtualization - [Core.ContentVirtualization] in the engine ini file now supports an array called 'DisabledAsset' which can be used to name asset types that should not virtualize their payloads. -- By default (in BaseEngine.ini) we have disabled the StaticMesh asset as we know it will crash if a payload is missing and the SoundWave asset as it still is pending testing. - This new way to disable virtualization is data driven. The older hard coded method has not been removed but will likely be reworked in a future submit. - Now when an editor bulkdata is adding it's payload to the package trailer builder during package save it will poll the virtualization system with a call to the new method ::IsDisabledForObject by passing in it's owner. -- If the owner is valid and was present in the 'DisabledAsset' array then the method will return true and the EPayloadFlags::DisableVirtualization flag will be applied. ### Package Trailer - The pre-existing functionality of enum EPayloadFilter has been moved to a new enum EPayloadStorageType as will only filter payloads based on their storage type. - EPayloadFilter has been modified to filter payloads based on functionality although at the moment the only thing it can filter for is to return payloads that can be virtualized, it is left for future expansion. - EPayloadFlags has been reduced to a uint16 with the remaining 2bytes being turned into a new member EPayloadFilterReason. - This new member allows us to record the exact reason why a payload is excluded from virtualization. If it is zero then the payload can virtualize, otherwise it will contain one or more reasons as to why it is being excluded. For this reason the enum is a bitfield. - Added overloads of ::GetPayloads and ::GetNumPayloads that take EPayloadFilter rather than a EPayloadStorageType - Added wrappers around all AccessMode types for FLookupTableEntry. - FPackageTrailerBuilder has been extended to take a EPayloadFilterReason so that the caller can already provide a reason why the payload cannot be virtualized. -- As a future peace of work this will probably be changed and we will ask the caller to pass in the owner UObject pointer instead and then we will process the filtering when building the package trailer to a) keep all of the filtering code in one place b) keep the filtering consistent ### PackageSubmissionChecks - The virtualization process in will now request the payloads that can be virtualized from the package trailer, which respects the new payload flag, rather than requesting all locally stored payloads. ### UObjects - There is no need for the SoundWave or MeshDescription classes to opt out of virtualization on construction. This will be done when the package is saved and is now data driven rather than being hardcoded. ### DumpPackagePayloadInfo - The command has been updated to also display the filter reasons applied to each payload [CL 20240971 by paul chipchase in ue5-main branch]
2022-05-17 07:54:28 -04:00
if (!FPackageTrailer::TryLoadFromPackage(Path, Trailer))
{
LogPackageError(Path);
continue;
}
}
else if (IFileManager::Get().FileExists(*PathString))
{
// IF we couldn't turn it into a FPackagePath it could be a path to a package not under any current mount point.
// So for a final attempt we will see if we can find the file on disk and load the package trailer that way.
It is now possible to disable virtualization for all payloads owned by a specific asset type by adding the name of the asset to [Core.ContentVirtualization]DisabledAsset string array in the engine ini file. #rb Per.Larsson #rnx #jira UE-151377 #preflight 628364050039ea57a52d6989 ### Virtualization - [Core.ContentVirtualization] in the engine ini file now supports an array called 'DisabledAsset' which can be used to name asset types that should not virtualize their payloads. -- By default (in BaseEngine.ini) we have disabled the StaticMesh asset as we know it will crash if a payload is missing and the SoundWave asset as it still is pending testing. - This new way to disable virtualization is data driven. The older hard coded method has not been removed but will likely be reworked in a future submit. - Now when an editor bulkdata is adding it's payload to the package trailer builder during package save it will poll the virtualization system with a call to the new method ::IsDisabledForObject by passing in it's owner. -- If the owner is valid and was present in the 'DisabledAsset' array then the method will return true and the EPayloadFlags::DisableVirtualization flag will be applied. ### Package Trailer - The pre-existing functionality of enum EPayloadFilter has been moved to a new enum EPayloadStorageType as will only filter payloads based on their storage type. - EPayloadFilter has been modified to filter payloads based on functionality although at the moment the only thing it can filter for is to return payloads that can be virtualized, it is left for future expansion. - EPayloadFlags has been reduced to a uint16 with the remaining 2bytes being turned into a new member EPayloadFilterReason. - This new member allows us to record the exact reason why a payload is excluded from virtualization. If it is zero then the payload can virtualize, otherwise it will contain one or more reasons as to why it is being excluded. For this reason the enum is a bitfield. - Added overloads of ::GetPayloads and ::GetNumPayloads that take EPayloadFilter rather than a EPayloadStorageType - Added wrappers around all AccessMode types for FLookupTableEntry. - FPackageTrailerBuilder has been extended to take a EPayloadFilterReason so that the caller can already provide a reason why the payload cannot be virtualized. -- As a future peace of work this will probably be changed and we will ask the caller to pass in the owner UObject pointer instead and then we will process the filtering when building the package trailer to a) keep all of the filtering code in one place b) keep the filtering consistent ### PackageSubmissionChecks - The virtualization process in will now request the payloads that can be virtualized from the package trailer, which respects the new payload flag, rather than requesting all locally stored payloads. ### UObjects - There is no need for the SoundWave or MeshDescription classes to opt out of virtualization on construction. This will be done when the package is saved and is now data driven rather than being hardcoded. ### DumpPackagePayloadInfo - The command has been updated to also display the filter reasons applied to each payload [CL 20240971 by paul chipchase in ue5-main branch]
2022-05-17 07:54:28 -04:00
if (!FPackageTrailer::TryLoadFromFile(PathString, Trailer))
{
LogPackageError(PathString);
continue;
}
}
else
{
UE_LOG(LogVirtualization, Error, TEXT("Arg '%s' could not be converted to a valid package path"), *Arg);
continue;
}
TArray<FIoHash> LocalPayloadIds = Trailer.GetPayloads(UE::EPayloadStorageType::Local);
TArray<FIoHash> VirtualizedPayloadIds = Trailer.GetPayloads(UE::EPayloadStorageType::Virtualized);
UE_LOG(LogVirtualization, Display, TEXT("")); // Blank line to make the output easier to read
UE_LOG(LogVirtualization, Display, TEXT("Package: '%s' has %d local and %d virtualized payloads"), *Path.GetDebugName(), LocalPayloadIds.Num(), VirtualizedPayloadIds.Num());
if (LocalPayloadIds.Num() > 0)
{
UE_LOG(LogVirtualization, Display, TEXT("LocalPayloads:"));
UE_LOG(LogVirtualization, Display, TEXT("Index | %-40s | SizeOnDisk | FilterReason"), TEXT("PayloadIdentifier"));
for (int32 Index = 0; Index < LocalPayloadIds.Num(); ++Index)
{
FPayloadInfo Info = Trailer.GetPayloadInfo(LocalPayloadIds[Index]);
Info.FilterFlags = UE::Virtualization::Utils::FixFilterFlags(PathString, Info.CompressedSize, Info.FilterFlags);
UE_LOG(LogVirtualization, Display, TEXT("%02d | %s | %-10s | %s"),
Index,
*LexToString(LocalPayloadIds[Index]),
*BytesToString(Info.CompressedSize),
*LexToString(Info.FilterFlags));
}
}
if (VirtualizedPayloadIds.Num() > 0)
{
UE_LOG(LogVirtualization, Display, TEXT("VirtualizedPayloads:"));
UE_LOG(LogVirtualization, Display, TEXT("Index|\t%-40s|\tFilterReason"), TEXT("PayloadIdentifier"));
for (int32 Index = 0; Index < VirtualizedPayloadIds.Num(); ++Index)
{
FPayloadInfo Info = Trailer.GetPayloadInfo(VirtualizedPayloadIds[Index]);
UE_LOG(LogVirtualization, Display, TEXT("%02d: |\t%s|\t%s"), Index, *LexToString(VirtualizedPayloadIds[Index]), *LexToString(Info.FilterFlags));
}
}
}
}
/**
* Note that this command is only valid when 'WITH_EDITORONLY_DATA 1' as virtualized payloads are not
* expected to exist at runtime.
*/
static FAutoConsoleCommand CCmdDumpPayloadToc = FAutoConsoleCommand(
TEXT("DumpPackagePayloadInfo"),
TEXT("Writes out information about a package's payloads to the log."),
FConsoleCommandWithArgsDelegate::CreateStatic(DumpPackagePayloadInfo));
#endif //WITH_EDITORONLY_DATA
} // namespace UE
#undef LOCTEXT_NAMESPACE