using UnityEngine.Experimental.Rendering; #if UNITY_STANDALONE_WIN using AMDUP = UnityEngine.AMD; #endif namespace UnityEngine.Rendering.PostProcessing { internal class FSR3NativeUpscaler: Upscaler { #if UNITY_STANDALONE_WIN public static bool IsSupported => LoadNativePlugin(); private static bool _nativePluginLoaded; private AMDUP.FSR2Context _nativeContext; private RenderTexture _tempColorInput; private RenderTexture _tempDepthInput; private RenderTexture _tempMotionVectorInput; private RenderTexture _tempColorOutput; public override void CreateContext(PostProcessRenderContext context, Upscaling config) { if (!LoadNativePlugin()) return; // Initialize FSR3 Upscaler context AMDUP.FfxFsr2InitializationFlags flags = 0; if (context.camera.allowHDR) flags |= AMDUP.FfxFsr2InitializationFlags.EnableHighDynamicRange; if (config.exposureSource == Upscaling.ExposureSource.Auto) flags |= AMDUP.FfxFsr2InitializationFlags.EnableAutoExposure; if (RuntimeUtilities.IsDynamicResolutionEnabled(context.camera)) flags |= AMDUP.FfxFsr2InitializationFlags.EnableDynamicResolution; if (SystemInfo.usesReversedZBuffer) flags |= AMDUP.FfxFsr2InitializationFlags.DepthInverted; AMDUP.FSR2CommandInitializationData initSettings = new() { maxRenderSizeWidth = (uint)config.MaxRenderSize.x, maxRenderSizeHeight = (uint)config.MaxRenderSize.y, displaySizeWidth = (uint)config.UpscaleSize.x, displaySizeHeight = (uint)config.UpscaleSize.y, ffxFsrFlags = flags, }; CommandBuffer cmd = new(); _nativeContext = AMDUP.GraphicsDevice.device.CreateFeature(cmd, in initSettings); Graphics.ExecuteCommandBuffer(cmd); cmd.Release(); CreateResources(context, config); } public override void DestroyContext() { base.DestroyContext(); if (_nativeContext != null) { CommandBuffer cmd = new(); AMDUP.GraphicsDevice.device.DestroyFeature(cmd, _nativeContext); Graphics.ExecuteCommandBuffer(cmd); cmd.Release(); _nativeContext = null; } DestroyResources(); } public override void Render(PostProcessRenderContext context, Upscaling config) { if (_nativeContext == null) return; var camera = context.camera; var cmd = context.command; cmd.BeginSample("FSR 3.1"); var scaledRenderSize = config.GetScaledRenderSize(context.camera); ref var execData = ref _nativeContext.executeData; execData.jitterOffsetX = -config.JitterOffset.x; execData.jitterOffsetY = -config.JitterOffset.y; execData.MVScaleX = -(float)scaledRenderSize.x; execData.MVScaleY = -(float)scaledRenderSize.y; execData.renderSizeWidth = (uint)scaledRenderSize.x; execData.renderSizeHeight = (uint)scaledRenderSize.y; execData.enableSharpening = config.performSharpenPass ? 1 : 0; execData.sharpness = config.sharpness; execData.frameTimeDelta = Time.unscaledDeltaTime * 1000f; execData.preExposure = config.preExposure; execData.reset = config.Reset ? 1 : 0; execData.cameraNear = camera.nearClipPlane; execData.cameraFar = camera.farClipPlane; execData.cameraFovAngleVertical = camera.fieldOfView * Mathf.Deg2Rad; PrepareInputs(cmd, context, config, _tempColorInput, _tempDepthInput, _tempMotionVectorInput); AMDUP.FSR2TextureTable textureTable = new() { colorInput = _tempColorInput, depth = _tempDepthInput, motionVectors = _tempMotionVectorInput, exposureTexture = config.exposureSource switch { Upscaling.ExposureSource.Manual when config.exposure != null => config.exposure, Upscaling.ExposureSource.Unity => context.autoExposureTexture, _ => null }, biasColorMask = null, reactiveMask = null, transparencyMask = config.transparencyAndCompositionMask, colorOutput = _tempColorOutput, }; if (config.autoGenerateReactiveMask || config.autoGenerateTransparencyAndComposition) { textureTable.biasColorMask = GenerateReactiveMask(cmd, context, config); } AMDUP.GraphicsDevice.device.ExecuteFSR2(cmd, _nativeContext, in textureTable); cmd.CopyTexture(_tempColorOutput, context.destination); cmd.EndSample("FSR 3.1"); } private void CreateResources(PostProcessRenderContext context, Upscaling config) { CreateRenderTexture(ref _tempColorInput, "FSR3 Color Input", config.MaxRenderSize, context.sourceFormat, true); CreateRenderTexture(ref _tempDepthInput, "FSR3 Depth Input", config.MaxRenderSize, GraphicsFormat.R32_SFloat, true); CreateRenderTexture(ref _tempMotionVectorInput, "FSR3 Motion Vector Input", config.MaxRenderSize, GraphicsFormat.R16G16_SFloat, true); CreateRenderTexture(ref _tempColorOutput, "FSR3 Color Output", config.UpscaleSize, context.sourceFormat, true); } private void DestroyResources() { DestroyRenderTexture(ref _tempColorOutput); DestroyRenderTexture(ref _tempMotionVectorInput); DestroyRenderTexture(ref _tempDepthInput); DestroyRenderTexture(ref _tempColorInput); } private static bool LoadNativePlugin() { if (_nativePluginLoaded) return true; if (SystemInfo.operatingSystemFamily == OperatingSystemFamily.Windows && SystemInfo.graphicsDeviceType is GraphicsDeviceType.Direct3D12 or GraphicsDeviceType.Vulkan) { try { _nativePluginLoaded = AMDUP.GraphicsDevice.device != null || AMDUP.GraphicsDevice.CreateGraphicsDevice() != null; if (_nativePluginLoaded) return true; } catch (System.DllNotFoundException) { _nativePluginLoaded = false; } } return _nativePluginLoaded; } #else public static bool IsSupported => false; public override void CreateContext(PostProcessRenderContext context, Upscaling config) { } public override void Render(PostProcessRenderContext context, Upscaling config) { } #endif } }