// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #define UE_MUTABLE_MAX_OPTIMIZATION 2 #include "HAL/IConsoleManager.h" #include "Engine/StreamableManager.h" #include "AssetRegistry/AssetData.h" #include "MuCO/CustomizableObjectInstance.h" #include "MuR/Parameters.h" #include "MuR/Image.h" #include "MuR/Types.h" #include "CustomizableObjectSystem.generated.h" #define UE_API CUSTOMIZABLEOBJECT_API class IConsoleVariable; class UCustomizableInstanceLODManagementBase; class ITargetPlatform; class UCustomizableObject; class USkeletalMesh; class UMaterialInterface; class UTexture2D; class UCustomizableObjectSystemPrivate; // This is used to hide Mutable SDK members in the public headers. class FUpdateContextPrivate; struct FFrame; struct FGuid; struct FEditorCompileSettings; extern TAutoConsoleVariable CVarClearWorkingMemoryOnUpdateEnd; extern TAutoConsoleVariable CVarReuseImagesBetweenInstances; extern TAutoConsoleVariable CVarPreserveUserLODsOnFirstGeneration; extern TAutoConsoleVariable CVarEnableMeshCache; extern TAutoConsoleVariable CVarEnableRealTimeMorphTargets; extern TAutoConsoleVariable CVarRollbackFixModelDiskStreamerDataRace; extern TAutoConsoleVariable CVarEnableReleaseMeshResources; extern TAutoConsoleVariable CVarFixLowPriorityTasksOverlap; UENUM(BlueprintType) enum class ECustomizableObjectOptimizationLevel : uint8 { None = 0, Minimal UE_DEPRECATED(5.6, "Converted internally to None. Use None instead.") = 1, Maximum = 2, FromCustomizableObject = 3 // Grab the optimization settings from the CO }; UENUM(BlueprintType) enum class ECustomizableObjectTextureCompression : uint8 { // Don't use texture compression None = 0, // Use Mutable's fast low-quality compression Fast, // Use Unreal's highest quality compression (100x slower to compress) HighQuality }; UENUM() enum class ECustomizableObjectNumBoneInfluences : uint8 { // The enum values can be used as the real numeric value of number of bone influences Four = 4, // Eight = 8, // Twelve = 12 // This is essentially the same as "Unlimited", but UE ultimately limits to 12 }; namespace EMutableProfileMetric { typedef uint8 Type; constexpr Type BuiltInstances = 1; constexpr Type UpdateOperations = 2; constexpr Type Count = 4; }; USTRUCT() struct FPendingReleaseMaterialsInfo { GENERATED_USTRUCT_BODY() UPROPERTY() TArray> Materials; UPROPERTY() int32 TicksUntilRelease = 0; }; /** Key to identify an image inside a generated mutable runtime instance. */ struct FMutableImageReference { /** Original image ID. Once generated it will be unique. However, future updates of the image may return a different ID for the * same image, if many other resources have been built in the middle. For this reason the rest of the data in the struct is what * must be used to request the additional mips. */ uint32 ImageID = 0; uint32 SurfaceId = 0; uint8 LOD = 0; /** Object component index. */ uint8 Component = 0; uint8 Image = 0; uint8 BaseMip = 0; TArray ConstantImagesNeededToGenerate; }; // Opaque representation of a possible registered value for texture parameters. struct FCustomizableObjectExternalTexture { FCustomizableObjectExternalTexture() = default; FString Name; FName Value; }; UCLASS(MinimalAPI, BlueprintType) class UCustomizableObjectSystem : public UObject { // Friends friend class UCustomizableObjectSystemPrivate; public: GENERATED_BODY() UCustomizableObjectSystem() = default; UE_API void InitSystem(); /** Get the singleton object. It will be created if it doesn't exist yet. */ UFUNCTION(BlueprintCallable, BlueprintPure, Category = Status) static UE_API UCustomizableObjectSystem* GetInstance(); UFUNCTION(BlueprintCallable, BlueprintPure, Category = Status) static UE_API UCustomizableObjectSystem* GetInstanceChecked(); /** Determines if the result of the instance update is valid or not. * @return true if the result is successful or has warnings, false if the result is from the Error category */ UFUNCTION(BlueprintCallable, Category = Status) static UE_API bool IsUpdateResultValid(const EUpdateResult UpdateResult); // Return true if the singleton has been created. It is different than GetInstance in that GetInstance will create it if it doesn't exist. static UE_API bool IsCreated(); /** Returns the current status of Mutable. Only when active is it possible to compile COs, generate instances, and stream textures. * @return True if Mutable is enabled. */ static UE_API bool IsActive(); // Begin UObject interface. UE_API virtual void BeginDestroy() override; UE_API virtual FString GetDesc() override; // End UObject interface. UE_API bool IsReplaceDiscardedWithReferenceMeshEnabled() const; UE_API void SetReplaceDiscardedWithReferenceMeshEnabled(bool bIsEnabled); #if WITH_EDITOR // Lock a CustomizableObjects, preventing the generation or update of any of its instances // Will return true if successful, false if it fails to lock because an update is already underway // This is usually only used in the editor UE_API bool LockObject(UCustomizableObject*); UE_API void UnlockObject(UCustomizableObject*); /** Checks if there are any outstanding disk or mip update operations in flight for the parameter Customizable Object that may * make it unsafe to compile at the moment. * @return true if there are operations in flight and it's not safe to compile */ UE_API bool CheckIfDiskOrMipUpdateOperationsPending(const UCustomizableObject& Object) const; // Called whenever the Mutable Editor Settings change, copying the new value of the current needed settings to the Customizable Object System UE_API void EditorSettingsChanged(const FEditorCompileSettings& InEditorSettings); // If true, uncompiled Customizable Objects will be compiled whenever an instance update is required UE_API bool IsAutoCompileEnabled() const; /** Return true if inside commandlets uncompiled Customizable Objects will be compiled whenever an instance update is required. */ UE_API bool IsAutoCompileCommandletEnabled() const; /** Set if inside commandlets uncompiled Customizable Objects will be compiled whenever an instance update is required. */ UE_API void SetAutoCompileCommandletEnabled(bool bValue); // If true, uncompiled Customizable Objects will be compiled synchronously UE_API bool IsAutoCompilationSync() const; #endif // Return the current MinLodQualityLevel for skeletal meshes. UE_API int32 GetSkeletalMeshMinLODQualityLevel() const; UE_API bool IsSupport16BitBoneIndexEnabled() const; UE_API bool IsProgressiveMipStreamingEnabled() const; UE_API void SetProgressiveMipStreamingEnabled(bool bIsEnabled); UE_API bool IsOnlyGenerateRequestedLODsEnabled() const; UE_API void SetOnlyGenerateRequestedLODsEnabled(bool bIsEnabled); #if WITH_EDITOR UE_API void SetImagePixelFormatOverride(const mu::FImageOperator::FImagePixelFormatFunc&); #endif // Show a warning on-screen and via a notification (if in Editor) and log an error when a CustomizableObject is // being used and it's not compiled. Callers can add additional information to the error log. UE_API void AddUncompiledCOWarning(const UCustomizableObject& InObject, FString const* OptionalLogInfo = nullptr); // Give access to the internal object data. UE_API UCustomizableObjectSystemPrivate* GetPrivate(); UE_API const UCustomizableObjectSystemPrivate* GetPrivate() const; UE_API UCustomizableInstanceLODManagementBase* GetInstanceLODManagement() const; // Pass a null ptr to reset to the default InstanceLODManagement UE_API void SetInstanceLODManagement(UCustomizableInstanceLODManagementBase* NewInstanceLODManagement); // Find out the version of the plugin UFUNCTION(BlueprintCallable, Category = Status) UE_API FString GetPluginVersion() const; // Get the number of instances built and alive. UFUNCTION(BlueprintCallable, Category = Status) UE_API int32 GetNumInstances() const; // Get the number of instances waiting to be updated. UFUNCTION(BlueprintCallable, Category = Status) UE_API int32 GetNumPendingInstances() const; // Get the total number of instances including built and not built. UFUNCTION(BlueprintCallable, Category = Status) UE_API int32 GetTotalInstances() const; // Get the amount of GPU memory in use in bytes for textures generated by mutable. UFUNCTION(BlueprintCallable, Category = Status) UE_API int64 GetTextureMemoryUsed() const; // Return the average build/update time of an instance in ms. UFUNCTION(BlueprintCallable, Category = Status) UE_API int32 GetAverageBuildTime() const; // If set to true, Mutable will release Mutable-generated textures immediately when they are no longer used without waiting for GC // IMPORTANT!!! Do NOT keep references to any Mutable generated textures or skeletal meshes if this is enabled, // they are owned by Mutable and will be destroyed without notice UFUNCTION(BlueprintCallable, Category = Status) UE_API void SetReleaseMutableTexturesImmediately(bool bReleaseTextures); UE_API bool IsMutableAnimInfoDebuggingEnabled() const; #if WITH_EDITOR // Get the maximum size a chunk can have on a specific platform. If unspecified return MUTABLE_STREAMED_DATA_MAXCHUNKSIZE UE_API uint64 GetMaxChunkSizeForPlatform(const ITargetPlatform* InTargetPlatform); #endif private: // Most of the work in this plugin happens here. UE_API bool Tick(float DeltaTime); /** Returns the number of remaining operations. */ UE_API int32 TickInternal(bool bBlocking); UE_API void DiscardInstances(); UE_API void ReleaseInstanceIDs(); public: /** Return true if the instance is being updated. */ UFUNCTION(BlueprintCallable, BlueprintPure, Category = CustomizableObjectSystem) UE_API bool IsUpdating(const UCustomizableObjectInstance* Instance) const; /** Set Mutable's working memory limit (kilobytes). Mutable will flush internal caches to try to keep its memory consumption below the WorkingMemory (i.e., it is not a hard limit). * The working memory limit will especially reduce the memory required to perform Instance Updates and Texture Streaming. * Notice that Mutable does not track all its memory (e.g., UObjects memory is no tracked). * This value can also be set using "mutable.WorkingMemory" CVar. */ UFUNCTION(BlueprintCallable, Category = CustomizableObjectSystem) UE_API void SetWorkingMemory(int32 KiloBytes); /** Get Mutable's working memory limit (kilobytes). See SetWorkingMemory(int32). */ UFUNCTION(BlueprintCallable, BlueprintPure, Category = CustomizableObjectSystem) UE_API int32 GetWorkingMemory() const; /** * Get if the mutable mesh cache for the instance meshes is enabled or not. * @param bCheckCVarOnGameThread Force the checking of the relevant CVar to use the GameThread as target thread * @return True if it is enabled and false otherwise */ static UE_API bool IsMeshCacheEnabled(bool bCheckCVarOnGameThread = false); /** * Get if mutable should clear its working memory between instance updates. * @return True if the clearing of memory will be performed, false otherwise. */ static UE_API bool ShouldClearWorkingMemoryOnUpdateEnd(); /** * Get if mutable will try to reuse textures in between instances. * @return True if mutable will try to reuse them, false otherwise. */ static UE_API bool ShouldReuseTexturesBetweenInstances(); private: UPROPERTY(Transient) TObjectPtr Private = nullptr; public: /** * Enables the collection of internal Mutable performance data. It has a performance cost. */ UE_API void EnableBenchmark(); /** * Disables the reporting of mutable instance benchmarking data. */ UE_API void EndBenchmark(); }; #undef UE_API