diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR2WrapperUpscaler.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR2WrapperUpscaler.cs
index db35fd5a..6243751f 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR2WrapperUpscaler.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR2WrapperUpscaler.cs
@@ -2,14 +2,24 @@
namespace UnityEngine.Rendering.HighDefinition.AMD.FSR2Wrapper
{
+ ///
+ /// Wrapper plugin that simply forwards calls to the original Unity native plugin implementation of FSR2.
+ /// Use this to verify other plugins against Unity's reference implementation.
+ ///
public class FSR2WrapperUpscaler: UpscalerPlugin
{
+ public override string name => "FSR 2.1";
+
+ public override bool isSupported => IsLoaded();
+
public override bool Load() => UnityEngine.AMD.AMDUnityPlugin.Load();
public override bool IsLoaded() => UnityEngine.AMD.AMDUnityPlugin.IsLoaded();
public override GraphicsDevice CreateGraphicsDevice() => new FSR2WrappedGraphicsDevice(UnityEngine.AMD.GraphicsDevice.CreateGraphicsDevice());
+ public override void DestroyGraphicsDevice() { } // Noop, native plugin does not allow clearing the graphics device
+
public override GraphicsDevice device => new FSR2WrappedGraphicsDevice(UnityEngine.AMD.GraphicsDevice.device);
public override uint version => UnityEngine.AMD.GraphicsDevice.version;
@@ -44,14 +54,12 @@ namespace UnityEngine.Rendering.HighDefinition.AMD.FSR2Wrapper
public override bool GetRenderResolutionFromQualityMode(FSR2Quality qualityMode, uint displayWidth, uint displayHeight, out uint renderWidth, out uint renderHeight)
{
- var quality = (UnityEngine.AMD.FSR2Quality)Math.Max(0, (int)qualityMode - 2);
- return _wrappedDevice.GetRenderResolutionFromQualityMode(quality, displayWidth, displayHeight, out renderWidth, out renderHeight);
+ return _wrappedDevice.GetRenderResolutionFromQualityMode((UnityEngine.AMD.FSR2Quality)qualityMode, displayWidth, displayHeight, out renderWidth, out renderHeight);
}
public override float GetUpscaleRatioFromQualityMode(FSR2Quality qualityMode)
{
- var quality = (UnityEngine.AMD.FSR2Quality)Math.Max(0, (int)qualityMode - 2);
- return _wrappedDevice.GetUpscaleRatioFromQualityMode(quality);
+ return _wrappedDevice.GetUpscaleRatioFromQualityMode((UnityEngine.AMD.FSR2Quality)qualityMode);
}
}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR3Upscaler.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR3Upscaler.cs
index e5b81547..3655235a 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR3Upscaler.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR3Upscaler.cs
@@ -3,10 +3,18 @@ using FidelityFX;
namespace UnityEngine.Rendering.HighDefinition.AMD.FSR3
{
+ ///
+ /// Custom upscaler plugin that uses the open source port of FSR3 to Unity.
+ /// This eschews using native plugins, instead using portable code that will work on any platform that supports compute shaders.
+ ///
public class FSR3UpscalerPlugin: UpscalerPlugin
{
private static FSR3GraphicsDevice sGraphicsDeviceInstance;
-
+
+ public override string name => "FSR 3.0";
+
+ public override bool isSupported => SystemInfo.supportsComputeShaders;
+
public override bool Load() => true;
public override bool IsLoaded() => true;
@@ -31,6 +39,15 @@ namespace UnityEngine.Rendering.HighDefinition.AMD.FSR3
return null;
}
+ public override void DestroyGraphicsDevice()
+ {
+ if (sGraphicsDeviceInstance != null)
+ {
+ sGraphicsDeviceInstance.Shutdown();
+ sGraphicsDeviceInstance = null;
+ }
+ }
+
public override GraphicsDevice device => sGraphicsDeviceInstance;
}
@@ -51,19 +68,22 @@ namespace UnityEngine.Rendering.HighDefinition.AMD.FSR3
internal void Shutdown()
{
+ foreach (var context in _contextPool)
+ {
+ context.Reset();
+ }
+
if (_assets != null)
{
Resources.UnloadAsset(_assets);
_assets = null;
}
-
- // TODO? destroy all FSR3 contexts on the stack
}
public override FSR2Context CreateFeature(CommandBuffer cmd, in FSR2CommandInitializationData initSettings)
{
var context = _contextPool.Count != 0 ? _contextPool.Pop() : new FSR3Context();
- context.Init(initSettings, _assets); // TODO might need some way to distinguish between contexts (see featureSlot)
+ context.Init(initSettings, _assets);
return context;
}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/UpscalerPlugin.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/UpscalerPlugin.cs
index ca2d4969..08f44c9b 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/UpscalerPlugin.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/UpscalerPlugin.cs
@@ -1,25 +1,105 @@
using System;
+using System.Collections.Generic;
+// This is placed in an AMD sub-namespace, to trick HDRP into using classes from here instead of from the UnityEngine.AMD namespace.
+// This allows us to intercept HDRP's upscaler calls and forward them to our own implementations, without having to modify the HDRP code itself.
namespace UnityEngine.Rendering.HighDefinition.AMD
{
public static class AMDUnityPlugin
{
- // TODO: allow dynamic switching between plugins (including shutdown of previous plugin)
- // internal static readonly UpscalerPlugin ActivePlugin = new FSR2Wrapper.FSR2WrapperUpscaler();
- internal static readonly UpscalerPlugin ActivePlugin = new FSR3.FSR3UpscalerPlugin();
+ private static readonly List AvailablePlugins = new()
+ {
+ new FSR3.FSR3UpscalerPlugin(),
+ new FSR2Wrapper.FSR2WrapperUpscaler(),
+ };
+
+ internal static UpscalerPlugin ActivePlugin = AvailablePlugins[0];
public static bool Load() => ActivePlugin.Load();
public static bool IsLoaded() => ActivePlugin.IsLoaded();
+
+ ///
+ /// Get the list of available upscaler plugins, as a read-only list.
+ /// Use this to display the available options and retrieve the index of the plugin you want to activate.
+ ///
+ public static IReadOnlyList GetAvailablePlugins()
+ {
+ return AvailablePlugins.AsReadOnly();
+ }
+
+ ///
+ /// Adds an upscaler plugin to the list of available plugins.
+ /// If a plugin of the same type already exists in the list, then the new plugin won't be added and the index of the existing plugin will be returned instead.
+ ///
+ /// The plugin to add
+ /// The index in the plugins list where the plugin can be found. Returns a negative number if the plugin could not be added.
+ public static int AddPlugin(UpscalerPlugin plugin)
+ {
+ if (plugin == null)
+ return -1;
+
+ // Check if we already have a plugin of the same type
+ var pluginType = plugin.GetType();
+ for (int i = 0; i < AvailablePlugins.Count; ++i)
+ {
+ if (AvailablePlugins[i].GetType() == pluginType)
+ return i;
+ }
+
+ AvailablePlugins.Add(plugin);
+ return AvailablePlugins.Count - 1;
+ }
+
+ ///
+ /// Sets the currently active upscaler plugin.
+ /// This deactivates the previously active plugin and creates a new device for the newly activated plugin.
+ /// If the chosen plugin is already active, then this won't do anything.
+ ///
+ /// The index in the available plugin list of the upscaler plugin to activate.
+ /// Whether the plugin was successfully changed and activated.
+ public static bool SetActivePlugin(int pluginIndex)
+ {
+ if (pluginIndex < 0 || pluginIndex >= AvailablePlugins.Count)
+ return false;
+
+ var newPlugin = AvailablePlugins[pluginIndex];
+ if (newPlugin == null || !newPlugin.isSupported)
+ return false;
+
+ if (newPlugin == ActivePlugin)
+ return true;
+
+ // If HDRP has previously created a graphics device, then it'll expect that to remain in place.
+ // Hence, make sure we automatically create a graphics device for the new plugin.
+ if (ActivePlugin != null && ActivePlugin.device != null)
+ {
+ var newDevice = newPlugin.CreateGraphicsDevice();
+ if (newDevice == null)
+ return false;
+
+ ActivePlugin.DestroyGraphicsDevice();
+ // TODO do we need to create a new "Feature" as well? Does HDRP cache this anywhere?
+ }
+
+ ActivePlugin = newPlugin;
+ return true;
+ }
}
public abstract class UpscalerPlugin
{
+ public abstract string name { get; }
+
+ public abstract bool isSupported { get; }
+
public abstract bool Load();
public abstract bool IsLoaded();
public abstract GraphicsDevice CreateGraphicsDevice();
+
+ public abstract void DestroyGraphicsDevice();
public abstract GraphicsDevice device { get; }
@@ -108,8 +188,6 @@ namespace UnityEngine.Rendering.HighDefinition.AMD
public enum FSR2Quality
{
- NativeAA,
- UltraQuality,
Quality,
Balanced,
Performance,