using System.Runtime.InteropServices; using FidelityFX; using UnityEngine.Experimental.Rendering; namespace UnityEngine.Rendering.PostProcessing { internal abstract class SGSR2Upscaler: Upscaler { public static bool IsSupported => SystemInfo.supportsComputeShaders; protected abstract string VariantName { get; } protected RenderTexture _colorLuma; protected RenderTexture _motionDepthAlpha; protected RenderTexture _motionDepthClipAlpha; protected readonly RenderTexture[] _lumaHistory = new RenderTexture[2]; protected readonly RenderTexture[] _upscaleHistory = new RenderTexture[2]; protected readonly ConstantsBuffer _paramsBuffer = new(); protected uint _frameCount = 0; public override void CreateContext(PostProcessRenderContext context, Upscaling config) { CreateRenderTexture(ref _colorLuma, "ColorLuma", config.MaxRenderSize, GraphicsFormat.R32_UInt, true); CreateRenderTexture(ref _motionDepthAlpha, "MotionDepthAlpha", config.MaxRenderSize, GraphicsFormat.R16G16B16A16_SFloat, true); CreateRenderTexture(ref _motionDepthClipAlpha, "MotionDepthClipAlpha", config.MaxRenderSize, GraphicsFormat.R16G16B16A16_SFloat, true); CreateRenderTextureArray(_lumaHistory, "LumaHistory", config.MaxRenderSize, GraphicsFormat.R32_UInt, true); CreateRenderTextureArray(_upscaleHistory, "History", config.UpscaleSize, context.sourceFormat, true); _paramsBuffer.Init(); } public override void DestroyContext() { base.DestroyContext(); _paramsBuffer.Destroy(); DestroyRenderTextureArray(_upscaleHistory); DestroyRenderTextureArray(_lumaHistory); DestroyRenderTexture(ref _motionDepthClipAlpha); DestroyRenderTexture(ref _motionDepthAlpha); DestroyRenderTexture(ref _colorLuma); } public override void Render(PostProcessRenderContext context, Upscaling config) { var cmd = context.command; cmd.BeginSample(VariantName); Matrix4x4 clipToPrevClip = Matrix4x4.identity; bool isCameraStill = false; if (_frameCount > 0 && !config.Reset) { // We need to use the projection matrix as it is used on the GPU to match what Unity keeps in Camera.previousViewProjectionMatrix Matrix4x4 viewProj = GL.GetGPUProjectionMatrix(context.camera.nonJitteredProjectionMatrix, true) * context.camera.worldToCameraMatrix; clipToPrevClip = context.camera.previousViewProjectionMatrix * viewProj.inverse; isCameraStill = IsCameraStill(viewProj, context.camera.previousViewProjectionMatrix); } ref var parms = ref _paramsBuffer.Value; parms.renderSize = config.GetScaledRenderSize(context.camera); parms.displaySize = config.UpscaleSize; parms.renderSizeRcp = new Vector2(1.0f / parms.renderSize.x, 1.0f / parms.renderSize.y); parms.displaySizeRcp = new Vector2(1.0f / parms.displaySize.x, 1.0f / parms.displaySize.y); parms.jitterOffset = config.JitterOffset; parms.clipToPrevClip = clipToPrevClip; parms.preExposure = config.preExposure; parms.cameraFovAngleHor = Mathf.Tan(context.camera.fieldOfView * Mathf.Deg2Rad * 0.5f) * (float)parms.renderSize.x / parms.renderSize.y; parms.cameraNear = context.camera.nearClipPlane; parms.minLerpContribution = 0f; parms.bSameCamera = isCameraStill ? 1u : 0u; parms.reset = config.Reset ? 1u : 0u; _paramsBuffer.UpdateBufferData(cmd); if (_frameCount == 0 || config.Reset) { cmd.SetRenderTarget(_lumaHistory[0]); cmd.ClearRenderTarget(false, true, Color.clear); cmd.SetRenderTarget(_lumaHistory[1]); cmd.ClearRenderTarget(false, true, Color.clear); cmd.SetRenderTarget(_upscaleHistory[0]); cmd.ClearRenderTarget(false, true, Color.clear); cmd.SetRenderTarget(_upscaleHistory[1]); cmd.ClearRenderTarget(false, true, Color.clear); } DoRender(cmd, context, config); cmd.EndSample(VariantName); _frameCount++; } protected abstract void DoRender(CommandBuffer cmd, PostProcessRenderContext context, Upscaling config); private static bool IsCameraStill(in Matrix4x4 currViewProj, in Matrix4x4 prevViewProj, float threshold = 1e-5f) { float vpDiff = 0f; for (int i = 0; i < 16; i++) { vpDiff += Mathf.Abs(currViewProj[i] - prevViewProj[i]); } return vpDiff < threshold; } } }