diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR2UpscalerPlugin.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR2UpscalerPlugin.cs
new file mode 100644
index 00000000..be5cd9f4
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR2UpscalerPlugin.cs
@@ -0,0 +1,121 @@
+using System.Collections.Generic;
+using FidelityFX;
+
+namespace UnityEngine.Rendering.HighDefinition.AMD.FSR2
+{
+ ///
+ /// Custom upscaler plugin that uses the open source port of FSR2 to Unity.
+ /// This eschews using native plugins, instead using portable code that will work on any platform that supports compute shaders.
+ ///
+ public class FSR2UpscalerPlugin: UpscalerPlugin
+ {
+ private Fsr2Assets _assets;
+
+ public override string name => "FSR 2.2";
+
+ public override bool isSupported => SystemInfo.supportsComputeShaders;
+
+ public override bool Load()
+ {
+ if (_assets != null)
+ return true;
+
+ _assets = Resources.Load("FSR2 Assets");
+ return _assets != null;
+ }
+
+ public override bool IsLoaded() => _assets != null;
+
+ public override UpscalerContext CreateContext(in FSR2CommandInitializationData initSettings)
+ {
+ var context = new FSR2UpscalerContext(in initSettings);
+ context.Init(_assets);
+ return context;
+ }
+
+ public override void DestroyContext(UpscalerContext context)
+ {
+ ((FSR2UpscalerContext)context).Destroy();
+ }
+
+ public override bool GetRenderResolutionFromQualityMode(FSR2Quality qualityMode, uint displayWidth, uint displayHeight, out uint renderWidth, out uint renderHeight)
+ {
+ Fsr3Upscaler.GetRenderResolutionFromQualityMode(out int rw, out int rh, (int)displayWidth, (int)displayHeight, (Fsr3Upscaler.QualityMode)((int)qualityMode + 2));
+ renderWidth = (uint)rw;
+ renderHeight = (uint)rh;
+ return true;
+ }
+
+ public override float GetUpscaleRatioFromQualityMode(FSR2Quality qualityMode)
+ {
+ return Fsr3Upscaler.GetUpscaleRatioFromQualityMode((Fsr3Upscaler.QualityMode)((int)qualityMode + 2));
+ }
+ }
+
+ public class FSR2UpscalerContext : UpscalerContext
+ {
+ private readonly Fsr2Context _context = new();
+ private readonly Fsr2.DispatchDescription _dispatchDescription = new();
+ private readonly FSR2CommandInitializationData _initData;
+
+ internal FSR2UpscalerContext(in FSR2CommandInitializationData initSettings)
+ {
+ _initData = initSettings;
+ }
+
+ internal void Init(Fsr2Assets assets)
+ {
+ Fsr2.InitializationFlags flags = Fsr2.InitializationFlags.EnableFP16Usage;
+ if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableHighDynamicRange)) flags |= Fsr2.InitializationFlags.EnableHighDynamicRange;
+ if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableDisplayResolutionMotionVectors)) flags |= Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors;
+ if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableMotionVectorsJitterCancellation)) flags |= Fsr2.InitializationFlags.EnableMotionVectorsJitterCancellation;
+ if (_initData.GetFlag(FfxFsr2InitializationFlags.DepthInverted)) flags |= Fsr2.InitializationFlags.EnableDepthInverted;
+ if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableDepthInfinite)) flags |= Fsr2.InitializationFlags.EnableDepthInfinite;
+ if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableAutoExposure)) flags |= Fsr2.InitializationFlags.EnableAutoExposure;
+ if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableDynamicResolution)) flags |= Fsr2.InitializationFlags.EnableDynamicResolution;
+
+ Debug.Log($"Initializing FSR2 with max render size: {_initData.maxRenderSizeWidth}x{_initData.maxRenderSizeHeight}, display size: {_initData.displaySizeWidth}x{_initData.displaySizeHeight}, flags: {flags}");
+
+ _context.Create(new Fsr2.ContextDescription
+ {
+ DisplaySize = new Vector2Int((int)_initData.displaySizeWidth, (int)_initData.displaySizeHeight),
+ MaxRenderSize = new Vector2Int((int)_initData.maxRenderSizeWidth, (int)_initData.maxRenderSizeHeight),
+ Flags = flags,
+ Shaders = assets.shaders,
+ });
+ }
+
+ internal void Destroy()
+ {
+ _context.Destroy();
+ }
+
+ public override void Execute(CommandBuffer cmd, in FSR2CommandExecutionData executeData, in FSR2TextureTable textures)
+ {
+ _dispatchDescription.Color = new ResourceView(textures.colorInput);
+ _dispatchDescription.Depth = new ResourceView(textures.depth);
+ _dispatchDescription.MotionVectors = new ResourceView(textures.motionVectors);
+ _dispatchDescription.Exposure = new ResourceView(textures.exposureTexture);
+ _dispatchDescription.Reactive = new ResourceView(textures.biasColorMask);
+ _dispatchDescription.TransparencyAndComposition = new ResourceView(textures.transparencyMask);
+ _dispatchDescription.Output = new ResourceView(textures.colorOutput);
+
+ _dispatchDescription.JitterOffset = new Vector2(executeData.jitterOffsetX, executeData.jitterOffsetY);
+ _dispatchDescription.MotionVectorScale = new Vector2(executeData.MVScaleX, executeData.MVScaleY);
+ _dispatchDescription.RenderSize = new Vector2Int((int)executeData.renderSizeWidth, (int)executeData.renderSizeHeight);
+ _dispatchDescription.InputResourceSize = new Vector2Int((int)executeData.renderSizeWidth, (int)executeData.renderSizeHeight);
+ _dispatchDescription.EnableSharpening = executeData.enableSharpening != 0;
+ _dispatchDescription.Sharpness = executeData.sharpness;
+ _dispatchDescription.FrameTimeDelta = executeData.frameTimeDelta / 1000f;
+ _dispatchDescription.PreExposure = executeData.preExposure;
+ _dispatchDescription.Reset = executeData.reset != 0;
+ _dispatchDescription.CameraNear = executeData.cameraNear;
+ _dispatchDescription.CameraFar = executeData.cameraFar;
+ _dispatchDescription.CameraFovAngleVertical = executeData.cameraFovAngleVertical;
+ _dispatchDescription.ViewSpaceToMetersFactor = 1.0f; // 1 unit is 1 meter in Unity
+ _dispatchDescription.UseTextureArrays = TextureXR.useTexArray && textures.colorInput.dimension == TextureDimension.Tex2DArray;
+
+ _context.Dispatch(_dispatchDescription, cmd);
+ }
+ }
+}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR2UpscalerPlugin.cs.meta b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR2UpscalerPlugin.cs.meta
new file mode 100644
index 00000000..fb49886b
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/FSR2UpscalerPlugin.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: d1949a73f3cda0f418c91ecd8212668c
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/Resources/FSR2 Assets.asset b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/Resources/FSR2 Assets.asset
new file mode 100644
index 00000000..e1c438e1
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/Resources/FSR2 Assets.asset
@@ -0,0 +1,23 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: db26e15a33db6ab42a38daab0ba2712f, type: 3}
+ m_Name: FSR2 Assets
+ m_EditorClassIdentifier:
+ shaders:
+ computeLuminancePyramidPass: {fileID: 7200000, guid: 04c3480675e29a340808141e68d4cc8b, type: 3}
+ reconstructPreviousDepthPass: {fileID: 7200000, guid: 5060dfafe45aa67459629186ceb7464e, type: 3}
+ depthClipPass: {fileID: 7200000, guid: b207de122e2c4b844b89dcd7c5c77c80, type: 3}
+ lockPass: {fileID: 7200000, guid: 20b7864a7e7258946aaf0f1996febad3, type: 3}
+ accumulatePass: {fileID: 7200000, guid: 7e791d69a5be98247a93b63897bc64df, type: 3}
+ sharpenPass: {fileID: 7200000, guid: 40815651f0f5d994cb73da9816a7ff9b, type: 3}
+ autoGenReactivePass: {fileID: 7200000, guid: 67ee1b32ca5e4234db9f06984c783dee, type: 3}
+ tcrAutoGenPass: {fileID: 7200000, guid: f8b1c27fb6a544b43b38903592240500, type: 3}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/Resources/FSR2 Assets.asset.meta b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/Resources/FSR2 Assets.asset.meta
new file mode 100644
index 00000000..41e9aa1f
--- /dev/null
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/Upscalers/Resources/FSR2 Assets.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8e31014ba9715c84d98f64c0cbe4cbad
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
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 55ba79f9..f99512b2 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
@@ -9,6 +9,7 @@ namespace UnityEngine.Rendering.HighDefinition.AMD
{
private static readonly List AvailablePlugins = new()
{
+ new FSR2.FSR2UpscalerPlugin(),
new FSR3.FSR3UpscalerPlugin(),
#if UNITY_STANDALONE_WIN && false
new FSR2Wrapper.FSR2WrapperUpscaler(),