diff --git a/Runtime/Common/FfxResourcesBase.cs b/Runtime/Common/FfxResourcesBase.cs index aac9e5c..8f1c58f 100644 --- a/Runtime/Common/FfxResourcesBase.cs +++ b/Runtime/Common/FfxResourcesBase.cs @@ -11,6 +11,22 @@ namespace FidelityFX { return new ComputeBuffer(count, Marshal.SizeOf()); } + + protected static Texture2D CreateLookup(string name, GraphicsFormat format, Color data) + { + var tex = new Texture2D(1, 1, format, TextureCreationFlags.None) { name = name }; + tex.SetPixel(0, 0, data); + tex.Apply(); + return tex; + } + + protected static Texture2D CreateLookup(string name, in Vector2Int size, GraphicsFormat format, T[] data) + { + var tex = new Texture2D(size.x, size.y, format, TextureCreationFlags.None) { name = name }; + tex.SetPixelData(data, 0); + tex.Apply(); + return tex; + } protected static RenderTexture CreateResource(string name, in Vector2Int size, GraphicsFormat format) { diff --git a/Runtime/Common/FfxUtils.cs b/Runtime/Common/FfxUtils.cs index 4d442da..3bd8d55 100644 --- a/Runtime/Common/FfxUtils.cs +++ b/Runtime/Common/FfxUtils.cs @@ -41,6 +41,19 @@ namespace FidelityFX { return Mathf.Abs(value) < Mathf.Epsilon ? 1.0f : Mathf.Sin(Mathf.PI * value) / (Mathf.PI * value) * (Mathf.Sin(0.5f * Mathf.PI * value) / (0.5f * Mathf.PI * value)); } + + public static float[] GenerateLanczos2Table(int width) + { + float[] lanczos2Weights = new float[width]; + for (int currentLanczosWidthIndex = 0; currentLanczosWidthIndex < width; ++currentLanczosWidthIndex) + { + float x = 2.0f * currentLanczosWidthIndex / (width - 1); + float y = Lanczos2(x); + lanczos2Weights[currentLanczosWidthIndex] = y; + } + + return lanczos2Weights; + } #if !UNITY_2021_1_OR_NEWER internal static void SetBufferData(this CommandBuffer commandBuffer, ComputeBuffer computeBuffer, Array data) @@ -49,4 +62,4 @@ namespace FidelityFX } #endif } -} \ No newline at end of file +} diff --git a/Runtime/FSR2/Fsr2Resources.cs b/Runtime/FSR2/Fsr2Resources.cs index 10edce2..e268040 100644 --- a/Runtime/FSR2/Fsr2Resources.cs +++ b/Runtime/FSR2/Fsr2Resources.cs @@ -51,13 +51,7 @@ namespace FidelityFX.FSR2 { // 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 = FfxUtils.Lanczos2(x); - lanczos2Weights[currentLanczosWidthIndex] = y; - } + float[] lanczos2Weights = FfxUtils.GenerateLanczos2Table(lanczos2LutWidth); float[] maximumBias = new float[MaximumBiasTextureWidth * MaximumBiasTextureHeight]; for (int i = 0; i < maximumBias.Length; ++i) @@ -67,24 +61,16 @@ namespace FidelityFX.FSR2 // 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 R32_SFloat and upload pre-normalized float data. - LanczosLut = new Texture2D(lanczos2LutWidth, 1, GraphicsFormat.R32_SFloat, TextureCreationFlags.None) { name = "FSR2_LanczosLutData" }; - LanczosLut.SetPixelData(lanczos2Weights, 0); - LanczosLut.Apply(); + LanczosLut = CreateLookup("FSR2_LanczosLutData", new Vector2Int(lanczos2LutWidth, 1), GraphicsFormat.R32_SFloat, lanczos2Weights); // Resource FSR2_MaximumUpsampleBias: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE - MaximumBiasLut = new Texture2D(MaximumBiasTextureWidth, MaximumBiasTextureHeight, GraphicsFormat.R32_SFloat, TextureCreationFlags.None) { name = "FSR2_MaximumUpsampleBias" }; - MaximumBiasLut.SetPixelData(maximumBias, 0); - MaximumBiasLut.Apply(); + MaximumBiasLut = CreateLookup("FSR2_MaximumUpsampleBias", new Vector2Int(MaximumBiasTextureWidth, MaximumBiasTextureHeight), GraphicsFormat.R32_SFloat, maximumBias); // 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.clear); - DefaultExposure.Apply(); + DefaultExposure = CreateLookup("FSR2_DefaultExposure", GraphicsFormat.R32G32_SFloat, Color.clear); // 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.clear); - DefaultReactive.Apply(); + DefaultReactive = CreateLookup("FSR2_DefaultReactivityMask", GraphicsFormat.R8_UNorm, Color.clear); // Resource FSR2_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE // Despite what the original FSR2 codebase says, this resource really isn't aliasable. Resetting this counter to 0 every frame breaks auto-exposure on MacOS Metal. diff --git a/Runtime/FSR3/Fsr3UpscalerResources.cs b/Runtime/FSR3/Fsr3UpscalerResources.cs index 3eef4a1..6a5f33d 100644 --- a/Runtime/FSR3/Fsr3UpscalerResources.cs +++ b/Runtime/FSR3/Fsr3UpscalerResources.cs @@ -55,32 +55,20 @@ namespace FidelityFX.FSR3 { // 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 = FfxUtils.Lanczos2(x); - lanczos2Weights[currentLanczosWidthIndex] = y; - } + float[] lanczos2Weights = FfxUtils.GenerateLanczos2Table(lanczos2LutWidth); Vector2Int maxRenderSize = contextDescription.MaxRenderSize; Vector2Int maxRenderSizeDiv2 = maxRenderSize / 2; // Resource FSR3UPSCALER_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 R32_SFloat and upload pre-normalized float data. - LanczosLut = new Texture2D(lanczos2LutWidth, 1, GraphicsFormat.R32_SFloat, TextureCreationFlags.None) { name = "FSR3UPSCALER_LanczosLutData" }; - LanczosLut.SetPixelData(lanczos2Weights, 0); - LanczosLut.Apply(); + LanczosLut = CreateLookup("FSR3UPSCALER_LanczosLutData", new Vector2Int(lanczos2LutWidth, 1), GraphicsFormat.R32_SFloat, lanczos2Weights); // Resource FSR3UPSCALER_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 = "FSR3UPSCALER_DefaultReactivityMask" }; - DefaultReactive.SetPixel(0, 0, Color.clear); - DefaultReactive.Apply(); + DefaultReactive = CreateLookup("FSR3UPSCALER_DefaultReactivityMask", GraphicsFormat.R8_UNorm, Color.clear); // Resource FSR3UPSCALER_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 = "FSR3UPSCALER_DefaultExposure" }; - DefaultExposure.SetPixel(0, 0, Color.clear); - DefaultExposure.Apply(); + DefaultExposure = CreateLookup("FSR3UPSCALER_DefaultExposure", GraphicsFormat.R32G32_SFloat, Color.clear); // Resource FSR3UPSCALER_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE // Despite what the original FSR3 codebase says, this resource really isn't aliasable. Resetting this counter to 0 every frame breaks auto-exposure on MacOS Metal.