using UnityEngine; using UnityEngine.Experimental.Rendering; namespace FidelityFX { internal class Fsr2Resources { public Texture2D DefaultExposure; public Texture2D DefaultReactive; public Texture2D LanczosLut; public RenderTexture AutoExposure; public readonly RenderTexture[] DilatedMotionVectors = new RenderTexture[2]; public readonly RenderTexture[] LockStatus = new RenderTexture[2]; public readonly RenderTexture[] InternalUpscaled = new RenderTexture[2]; public readonly RenderTexture[] LumaHistory = new RenderTexture[2]; public void Create(Fsr2.ContextDescription contextDescription) { // Generate the data for the LUT const int lanczos2LutWidth = 128; float[] lanczos2Weights = new float[lanczos2LutWidth]; for (int currentLanczosWidthIndex = 0; currentLanczosWidthIndex < lanczos2LutWidth; ++currentLanczosWidthIndex) { float x = 2.0f * currentLanczosWidthIndex / (lanczos2LutWidth - 1); float y = Fsr2.Lanczos2(x); lanczos2Weights[currentLanczosWidthIndex] = y; } // TODO: create resources, i.e. render textures used for intermediate results. // Note that "aliasable" resources should be equivalent to GetTemporary render textures // UAVs *may* be an issue with the PS4 not handling simultaneous reading and writing to an RT properly // Unity does have Graphics.SetRandomWriteTarget for enabling UAV on ComputeBuffers or RTs // Unity doesn't do 1D textures so just default to Texture2D // Resource FSR2_LanczosLutData: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE // R16_SNorm textures are not supported by Unity on most platforms, strangely enough. So instead we use R16_SFloat and upload pre-normalized float data. LanczosLut = new Texture2D(lanczos2LutWidth, 1, GraphicsFormat.R16_SFloat, TextureCreationFlags.None) { name = "FSR2_LanczosLutData" }; LanczosLut.SetPixelData(lanczos2Weights, 0); LanczosLut.Apply(); // Resource FSR2_DefaultExposure: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE DefaultExposure = new Texture2D(1, 1, GraphicsFormat.R32G32_SFloat, TextureCreationFlags.None) { name = "FSR2_DefaultExposure" }; DefaultExposure.SetPixel(0, 0, Color.black); DefaultExposure.Apply(); // Resource FSR2_DefaultReactivityMask: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE DefaultReactive = new Texture2D(1, 1, GraphicsFormat.R8_UNorm, TextureCreationFlags.None) { name = "FSR2_DefaultReactivityMask" }; DefaultReactive.SetPixel(0, 0, Color.black); DefaultReactive.Apply(); // Resource FSR2_AutoExposure: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE AutoExposure = new RenderTexture(1, 1, 1, GraphicsFormat.R32G32_SFloat) { name = "FSR2_AutoExposure", enableRandomWrite = true }; AutoExposure.Create(); // Resources FSR2_InternalDilatedVelocity1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_NONE CreateDoubleBufferedResource(DilatedMotionVectors, "FSR2_InternalDilatedVelocity", contextDescription.MaxRenderSize, GraphicsFormat.R16G16_SFloat); // Resources FSR2_LockStatus1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_NONE CreateDoubleBufferedResource(LockStatus, "FSR2_LockStatus", contextDescription.DisplaySize, GraphicsFormat.R16G16_SFloat); // Resources FSR2_InternalUpscaled1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT, FFX_RESOURCE_FLAGS_NONE CreateDoubleBufferedResource(InternalUpscaled, "FSR2_InternalUpscaled", contextDescription.DisplaySize, GraphicsFormat.R16G16B16A16_SFloat); // Resources FSR2_LumaHistory1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8G8B8A8_UNORM, FFX_RESOURCE_FLAGS_NONE CreateDoubleBufferedResource(LumaHistory, "FSR2_LumaHistory", contextDescription.DisplaySize, GraphicsFormat.R8G8B8A8_UNorm); } private static void CreateDoubleBufferedResource(RenderTexture[] resource, string name, Vector2Int size, GraphicsFormat format) { for (int i = 0; i < 2; ++i) { resource[i] = new RenderTexture(size.x, size.y, 1, format) { name = name + (i + 1), enableRandomWrite = true }; resource[i].Create(); } } public void Destroy() { DestroyResource(LumaHistory); DestroyResource(InternalUpscaled); DestroyResource(LockStatus); DestroyResource(DilatedMotionVectors); DestroyResource(ref AutoExposure); DestroyResource(ref DefaultReactive); DestroyResource(ref DefaultExposure); DestroyResource(ref LanczosLut); } private static void DestroyResource(ref Texture2D resource) { if (resource == null) return; Object.Destroy(resource); resource = null; } private static void DestroyResource(ref RenderTexture resource) { if (resource == null) return; resource.Release(); resource = null; } private static void DestroyResource(RenderTexture[] resource) { for (int i = 0; i < resource.Length; ++i) DestroyResource(ref resource[i]); } } }