Adaptive Performance provider guide
Adaptive Performance requires platform providers to supply it with necessary data. Loaders, such as the Samsung (Android) provider, are generally provided via their own package, with the exception of the device Simulator (Desktop) extension.
Lifecycle management
The Adaptive Performance management code enables you to manage the lifecycle of Adaptive Performance providers without the need for boilerplate code. The AdaptivePerformanceManagerSettings
class provides a scriptable object that an app can use to start, stop, initialize, and deinitialize a set of subsystems defined in an AdaptivePerformanceLoader
instance. Your Adaptive Performance provider uses this as the main driver.
Providers must create a subclass of AdaptivePerformanceLoader
to make a loader available for their particular runtime scheme.
The AdaptivePerformanceLoader
interface looks like this:
public abstract class AdaptivePerformanceLoader : ScriptableObject
{
public virtual bool Initialize() { return false; }
public virtual bool Start() { return false; }
public virtual bool Stop() { return false; }
public virtual bool Deinitialize() { return false; }
public abstract T GetLoadedSubsystem<T>() where T : class, ISubsystem;
public abstract ISubsystem GetDefaultSubsystem();
public abstract IAdaptivePerformanceSettings GetSettings();
}
To handle subsystem management in a type-safe manner, derive from the AdaptivePerformanceLoaderHelper
class. For an example, see /Editor/DeviceSimulator/Management/SimulatorProviderLoader.cs
.
An AdaptivePerformanceLoader
is a ScriptableObject, which means you can create one or more instances of it. Each AdaptivePerformanceLoader
subclass defines the subsystems and their load order, and manages the set of subsystems they require.
Add all the AdaptivePerformanceLoader
instances you created to the Loaders property of the Adaptive Performance Manager Settings, and arrange them in the order you want them to load. When initializing Loaders, Adaptive Performance Manager Settings calls each AdaptivePerformanceLoader
instance it has a reference to, in the order you specify, and attempts to initialize each one. The first loader to initialize successfully becomes the active loader, and Unity stops all further attempts to initialize other loaders. Once that happens, you can query the static AdaptivePerformanceManagerSettings.ActiveLoader
instance to access the active loader. If all loaders fail to initialize, Unity sets activeLoader
to null.
Scene-based automatic lifecycle management hooks into the following MonoBehaviour
callback points:
Callback | Lifecycle step |
---|---|
OnEnable | Find the first loader that initialized successfully and set ActiveLoader . |
Start | Start all subsystems. |
OnDisable | Stop all subsystems. |
OnDestroy | Deinitialize all subsystems and remove the ActiveLoader instance. |
Application lifetime-based automatic lifecycle management hooks into the following callback points:
Callback | Lifecycle step |
---|---|
Runtime initialization after assemblies loaded | Find the first Loader that succeeds initialization and set ActiveLoader . |
Runtime initialization before splash screen displays | Start all subsystems. |
OnDisable | Stop all subsystems. |
OnDestroy | Deintialize all subsystems and remove the ActiveLoader instance. |
Configuring build and runtime settings through Project Settings
A provider might need additional settings to help manage build issues or runtime configuration. To do this, add an AdaptivePerformanceConfigurationData
attribute to a ScriptableObject, and define a set of properties you want to surface to allow users to control configuration. Unity displays configuration options in the Adaptive Performance section of the Project Settings window.
Unity manages the lifecycle of one instance of the class marked with the attribute through the EditorBuildSettings config object API. If you don't provide a dedicated UI, configuration settings are displayed in the Project Settings window using the standard Scriptable Object UI Inspector. You can create a custom Editor for your configuration settings type, which then replaces the standard Inspector in the Project Settings window.
The provider needs to handle getting the settings from EditorUserBuildSettings
into the built application. You can do this with a custom build processing script. If you only need to make sure that you have access to the same settings at runtime, you can derive from AdaptivePerformanceBuildHelper<T>
. This is a generic abstract base class that takes the build settings stored in EditorUserBuildSettings
and gets them into the built application for runtime access.
The simplest build script for your package would look like this:
public class MyBuildProcessor : AdaptivePerformanceBuildHelper<MySettings>
{
public override string BuildSettingsKey { get { return "MyPackageSettingsKey"; } }
}
You can override the build processing steps from IPreprocessBuildWithReport
and IPostprocessBuildWithReport
, but make sure you call to the base class implementation. If you don’t, your settings won't transfer to the built application.
public class MyBuildProcessor : AdaptivePerformanceBuildHelper<MySettings>
{
public override string BuildSettingsKey { get { return "MyPackageSettingsKey"; } }
public override void OnPreprocessBuild(BuildReport report)
{
base.OnPreprocessBuild(report);
// Do your work here
}
public override void OnPostprocessBuild(BuildReport report)
{
base.OnPreprocessBuild(report);
// Do your work here
}
}
If you want to support different settings per platform at build time, you can override UnityEngine.Object SettingsForBuildTargetGroup(BuildTargetGroup buildTargetGroup)
and use the buildTargetGroup
attribute to retrieve the appropriate platform settings. By default, this method uses the key associated with the settings instance to copy the entire settings object from EditorUserBuildSettings
to PlayerSettings
.
public class MyBuildProcessor : AdaptivePerformanceBuildHelper<MySettings>
{
public override string BuildSettingsKey { get { return "MyPackageSettingsKey"; } }
public override UnityEngine.Object SettingsForBuildTargetGroup(BuildTargetGroup buildTargetGroup)
{
// Get platform specific settings and return them. Use something like the following
// for simple settings data that isn't platform specific.
UnityEngine.Object settingsObj = null;
EditorBuildSettings.TryGetConfigObject(BuildSettingsKey, out settingsObj);
if (settingsObj == null || !(settingsObj is T))
return null;
return settingsObj;
}
}
Package metadata
Your provider must provide metadata information for it to be usable by the Adaptive Performance provider management system. Your provider must implement the following interfaces:
- IAdaptivePerformancePackage
- IAdaptivePerformancePackageMetadata
- IAdaptivePerformanceLoaderMetadata
The system will use .NET reflection to find all types implementing the IAdaptivePerformancePackage interface. It will then attempt to instantiate each one and populate the metadata store with the information provided by each instance.
Example: Simple, minimal package information setup
class MyPackage : IAdaptivePerformancePackage
{
private class MyLoaderMetadata : IAdaptivePerformanceLoaderMetadata
{
public string loaderName { get; }
public string loaderType { get; }
public List<BuildTargetGroup> supportedBuildTargets { get; }
}
private class MyPackageMetadata : IAdaptivePerformancePackageMetadata
{
public string packageName { get; }
public string packageId { get; }
public string settingsType { get; }
public List<IAdaptivePerformanceLoaderMetadata> loaderMetadata { get; }
}
private static IAdaptivePerformancePackageMetadata s_Metadata = new MyPackageMetadata(){
packageName = "My AdaptivePerformance Provider",
packageId = "my.AdaptivePerformance.package",
settingsType = "My.Package.MyPackageSettings",
loaderMetadata = new List<IAdaptivePerformanceLoaderMetadata>() {
new MyLoaderMetadata() {
loaderName = "My Loader",
loaderType = "My.Package.MyLoader",
supportedBuildTargets = new List<BuildTargetGroup>() {
BuildTargetGroup.Standalone,
BuildTargetGroup.Android,
BuildTargetGroup.iOS
}
},
}
};
public IAdaptivePerformancePackageMetadata metadata => s_Metadata;
public bool PopulateNewSettingsInstance(ScriptableObject obj)
{
MyPackageSettings packageSettings = obj as MyPackageSettings;
if (packageSettings != null)
{
// Do something here if you need to...
}
return false;
}
}
Package initialization
Implementing the Package Metadata allows the Adaptive Performance provider management system to automatically create and initialize your loaders and settings instances. The system will pass any new instances of your settings to the PopulateNewSettingsInstance
method to allow your provider to initialize the new instance data after it's created, if needed.
Installing the Adaptive Performance provider management
Adaptive Performance includes the provider management, so you shouldn't need to install it. If you do need to install it, follow the instructions in the Package Manager documentation.
Adaptive Performance Provider Management Content
This version of Adaptive Performance contains the following:
Feature | Description |
---|---|
AdaptivePerformanceManagerSettings | ScriptableObject that you can use to manage AdaptivePerformanceLoader instances and their lifecycle. |
AdaptivePerformanceLoader | Base class all loaders should derive from. It provides a basic API that the AdaptivePerformanceManagerSettings can use to manage lifecycle, and a simple API you can use to request specific subsystems from the loader. |
AdaptivePerformanceConfigurationData | Attribute that allows for build and runtime settings to be hosted in the Adaptive Performance section of the Project Settings window. All instances use the name supplied in the script as part of the attribute. The management feature uses the EditorBuildSettings config object API, stored with the key provided in the attribute, to maintain and manage the lifecycle for one instance of the build settings. To access the configuration settings instance, retrieve the instance associated with the chosen key (as set in the attribute) from EditorBuildSettings. |
AdaptivePerformancePackageInitializationBase | Helper class to derive from that simplifies package initialization. Helps to create default instances of the package's AdaptivePerformanceLoader and default settings when you install the package. Initialization only runs once, and you shouldn't depend on the user to create the specified instances on their own. |
AdaptivePerformanceBuildHelper | Abstract class useful for handling some of the boilerplate around moving settings from the Editor to the runtime. If you derive from this class and specify the appropriate settings type, the system moves settings of that type from EditorUserBuildSettings to PlayerSettings so they can be used at runtime. |
AdaptivePerformanceGeneralSettings | Contains settings that apply to all Adaptive Performance Providers, rather than any single provider. |