using System.Collections.Generic; 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 Fsr3UpscalerAssets _assets; public override string name => "FSR 3.1"; public override bool isSupported => SystemInfo.supportsComputeShaders; public override bool Load() { if (_assets != null) return true; _assets = Resources.Load("FSR3 Upscaler Assets"); return _assets != null; } public override bool IsLoaded() => _assets != null; public override UpscalerContext CreateContext(in FSR2CommandInitializationData initSettings) { var context = new FSR3UpscalerContext(in initSettings); context.Init(_assets); return context; } public override void DestroyContext(UpscalerContext context) { ((FSR3UpscalerContext)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 FSR3UpscalerContext : UpscalerContext { private readonly Fsr3UpscalerContext _context = new(); private readonly Fsr3Upscaler.DispatchDescription _dispatchDescription = new(); private readonly FSR2CommandInitializationData _initData; internal FSR3UpscalerContext(in FSR2CommandInitializationData initSettings) { _initData = initSettings; } internal void Init(Fsr3UpscalerAssets assets) { Fsr3Upscaler.InitializationFlags flags = Fsr3Upscaler.InitializationFlags.EnableFP16Usage; if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableHighDynamicRange)) flags |= Fsr3Upscaler.InitializationFlags.EnableHighDynamicRange; if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableDisplayResolutionMotionVectors)) flags |= Fsr3Upscaler.InitializationFlags.EnableDisplayResolutionMotionVectors; if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableMotionVectorsJitterCancellation)) flags |= Fsr3Upscaler.InitializationFlags.EnableMotionVectorsJitterCancellation; if (_initData.GetFlag(FfxFsr2InitializationFlags.DepthInverted)) flags |= Fsr3Upscaler.InitializationFlags.EnableDepthInverted; if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableDepthInfinite)) flags |= Fsr3Upscaler.InitializationFlags.EnableDepthInfinite; if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableAutoExposure)) flags |= Fsr3Upscaler.InitializationFlags.EnableAutoExposure; if (_initData.GetFlag(FfxFsr2InitializationFlags.EnableDynamicResolution)) flags |= Fsr3Upscaler.InitializationFlags.EnableDynamicResolution; Debug.Log($"Initializing FSR3 with max render size: {_initData.maxRenderSizeWidth}x{_initData.maxRenderSizeHeight}, display size: {_initData.displaySizeWidth}x{_initData.displaySizeHeight}, flags: {flags}"); _context.Create(new Fsr3Upscaler.ContextDescription { MaxUpscaleSize = 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.UpscaleSize = new Vector2Int((int)_initData.displaySizeWidth, (int)_initData.displaySizeHeight); _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); } } }