From bf9190d963b07c3c5de9bae7c1421bf0f162336b Mon Sep 17 00:00:00 2001 From: Torgo13 Date: Wed, 15 May 2024 18:52:58 +0100 Subject: [PATCH] Implemented Snapdragon Game Super Resolution --- .../Runtime/PostProcessing/Shaders/sgsr.meta | 8 ++ .../PostProcessing/Shaders/sgsr/LICENSE | 29 ++++ .../PostProcessing/Shaders/sgsr/LICENSE.meta | 7 + .../Shaders/sgsr/sgsr_mobile.hlsl | 130 ++++++++++++++++++ .../Shaders/sgsr/sgsr_mobile.hlsl.meta | 27 ++++ .../Data/UniversalRenderPipelineAsset.cs | 6 + .../Runtime/Passes/PostProcessPass.cs | 9 +- .../Runtime/UniversalRenderPipeline.cs | 7 + .../Runtime/UniversalRenderPipelineCore.cs | 6 + .../Shaders/PostProcessing/FinalPost.shader | 52 ++++++- 10 files changed, 279 insertions(+), 2 deletions(-) create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr.meta create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/LICENSE create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/LICENSE.meta create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/sgsr_mobile.hlsl create mode 100644 Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/sgsr_mobile.hlsl.meta diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr.meta b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr.meta new file mode 100644 index 00000000000..0378869041f --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d9b19982aed923e418ed37258a6a7729 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/LICENSE b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/LICENSE new file mode 100644 index 00000000000..d9d513c7585 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/LICENSE @@ -0,0 +1,29 @@ +Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +SPDX-License-Identifier: BSD-3-Clause \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/LICENSE.meta b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/LICENSE.meta new file mode 100644 index 00000000000..cd5a974ad49 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0784c039be2675c41a8c0f8460805ef3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/sgsr_mobile.hlsl b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/sgsr_mobile.hlsl new file mode 100644 index 00000000000..bbc9cfe9118 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/sgsr_mobile.hlsl @@ -0,0 +1,130 @@ +//============================================================================================================ +// +// +// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause +// +//============================================================================================================ + +//////////////////////// +// USER CONFIGURATION // +//////////////////////// + +/* +* Operation modes: +* RGBA -> 1 +* RGBY -> 3 +* LERP -> 4 +*/ +#define OperationMode 1 + +#define EdgeThreshold 8.0/255.0 + +#define EdgeSharpness 2.0 + +//////////////////////// +//////////////////////// +//////////////////////// + +// ///////SGSR_GL_Mobile.frag///////////////////////////////////////// +#if defined(SGSR_MOBILE) +half fastLanczos2(half x) +{ + half wA = x- half(4.0); + half wB = x*wA-wA; + wA *= wA; + return wB*wA; +} +half2 weightY(half dx, half dy, half c, half std) +{ + half x = ((dx*dx)+(dy* dy))* half(0.5) + clamp(abs(c)*std, 0.0, 1.0); + half w = fastLanczos2(x); + return half2(w, w * c); +} + +void SgsrYuvH( + out half4 pix, + float2 uv, + float4 con1) +{ + const int mode = OperationMode; + half edgeThreshold = EdgeThreshold; + half edgeSharpness = EdgeSharpness; + + // Sample the low res texture using current texture coordinates (in UV space). + if(mode == 1) + pix.xyz = SGSRRGBH(uv).xyz; + else + pix.xyzw = SGSRRGBH(uv).xyzw; + float xCenter; + xCenter = abs(uv.x+-0.5); + float yCenter; + yCenter = abs(uv.y+-0.5); + + //todo: config the SR region based on needs + //if ( mode!=4 && xCenter*xCenter+yCenter*yCenter<=0.4 * 0.4) + if ( mode!=4) + { + // Compute the coordinate for the center of the texel in image space. + float2 imgCoord = ((uv.xy*con1.zw)+ float2(-0.5,0.5)); + float2 imgCoordPixel = floor(imgCoord); + // Remap the coordinate for the center of the texel in image space to UV space. + float2 coord = (imgCoordPixel*con1.xy); + half2 pl = (imgCoord+(-imgCoordPixel)); + // Gather the `[mode]` components (ex: `.y` if mode is 1) of the 4 texels located around `coord`. + half4 left = SGSRH(coord, mode); + + half edgeVote = abs(left.z - left.y) + abs(pix[mode] - left.y) + abs(pix[mode] - left.z) ; + if(edgeVote > edgeThreshold) + { + // Shift coord to the right by 1 texel. `coord` will be pointing to the same texel originally sampled + // l.84 or 86 (The texel at UV in_TEXCOORD0 in the low res texture). + coord.x += con1.x; + + // Gather components for the texels located to the right of coord (the original sampled texel). + half4 right = SGSRH(coord + float2(con1.x, 0.0), mode); + // Gather components for the texels located to up and down of coord (the original sampled texel). + half4 upDown; + upDown.xy = SGSRH(coord + float2(0.0, -con1.y), mode).wz; + upDown.zw = SGSRH(coord + float2(0.0, con1.y), mode).yx; + + half mean = (left.y+left.z+right.x+right.w)* half(0.25); + left = left - half4(mean,mean,mean,mean); + right = right - half4(mean, mean, mean, mean); + upDown = upDown - half4(mean, mean, mean, mean); + pix.w =pix[mode] - mean; + + half sum = (((((abs(left.x)+abs(left.y))+abs(left.z))+abs(left.w))+(((abs(right.x)+abs(right.y))+abs(right.z))+abs(right.w)))+(((abs(upDown.x)+abs(upDown.y))+abs(upDown.z))+abs(upDown.w))); + half std = half(2.181818)/sum; + + half2 aWY = weightY(pl.x, pl.y+1.0, upDown.x,std); + aWY += weightY(pl.x-1.0, pl.y+1.0, upDown.y,std); + aWY += weightY(pl.x-1.0, pl.y-2.0, upDown.z,std); + aWY += weightY(pl.x, pl.y-2.0, upDown.w,std); + aWY += weightY(pl.x+1.0, pl.y-1.0, left.x,std); + aWY += weightY(pl.x, pl.y-1.0, left.y,std); + aWY += weightY(pl.x, pl.y, left.z,std); + aWY += weightY(pl.x+1.0, pl.y, left.w,std); + aWY += weightY(pl.x-1.0, pl.y-1.0, right.x,std); + aWY += weightY(pl.x-2.0, pl.y-1.0, right.y,std); + aWY += weightY(pl.x-2.0, pl.y, right.z,std); + aWY += weightY(pl.x-1.0, pl.y, right.w,std); + + half finalY = aWY.y/aWY.x; + + half max4 = max(max(left.y,left.z),max(right.x,right.w)); + half min4 = min(min(left.y,left.z),min(right.x,right.w)); + finalY = clamp(edgeSharpness*finalY, min4, max4); + + half deltaY = finalY -pix.w; + + pix.x = saturate((pix.x+deltaY)); + pix.y = saturate((pix.y+deltaY)); + pix.z = saturate((pix.z+deltaY)); + } + } + pix.w = 1.0; //assume alpha channel is not used + +} +#endif +//////////////////////////////////////////////////////////////////////// diff --git a/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/sgsr_mobile.hlsl.meta b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/sgsr_mobile.hlsl.meta new file mode 100644 index 00000000000..c9fa5182513 --- /dev/null +++ b/Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/sgsr_mobile.hlsl.meta @@ -0,0 +1,27 @@ +fileFormatVersion: 2 +guid: 107bc422565fc5443a1df1419ea7ba81 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs index b4d4e849c71..f08b19ea4b6 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs @@ -374,6 +374,12 @@ public enum UpscalingFilterSelection [InspectorName("FidelityFX Super Resolution 1.0"), Tooltip("If the target device does not support Unity shader model 4.5, Unity falls back to the Automatic option.")] FSR, + /// + /// Unity uses the Snapdragon Game Super Resolution technique to perform upscaling. + /// + [InspectorName("Snapdragon Game Super Resolution")] + SGSR, + /// /// Unity uses the Spatial-Temporal Post-Processing technique to perform upscaling. /// diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs index dbac1d62450..de3d03b838a 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs @@ -1689,6 +1689,7 @@ void RenderFinalPass(CommandBuffer cmd, ref RenderingData renderingData) // FSR is only considered "enabled" when we're performing upscaling. (downscaling uses a linear filter unconditionally) bool isFsrEnabled = ((cameraData.imageScalingMode == ImageScalingMode.Upscaling) && (cameraData.upscalingFilter == ImageUpscalingFilter.FSR)); + bool isSgsrEnabled = ((cameraData.imageScalingMode == ImageScalingMode.Upscaling) && (cameraData.upscalingFilter == ImageUpscalingFilter.SGSR)); // Reuse RCAS pass as an optional standalone post sharpening pass for TAA. // This avoids the cost of EASU and is available for other upscaling options. @@ -1704,7 +1705,7 @@ void RenderFinalPass(CommandBuffer cmd, ref RenderingData renderingData) // NOTE: An ideal implementation could inline this color conversion logic into the UberPost pass, but the current code structure would make // this process very complex. Specifically, we'd need to guarantee that the uber post output is always written to a UNORM format render // target in order to preserve the precision of specially encoded color data. - bool isSetupRequired = (isFxaaEnabled || isFsrEnabled); + bool isSetupRequired = (isFxaaEnabled || isFsrEnabled || isSgsrEnabled); // Make sure to remove any MSAA and attached depth buffers from the temporary render targets var tempRtDesc = cameraData.cameraTargetDescriptor; @@ -1799,6 +1800,12 @@ void RenderFinalPass(CommandBuffer cmd, ref RenderingData renderingData) break; } + + case ImageUpscalingFilter.SGSR: + { + material.EnableKeyword(ShaderKeywordStrings.Sgsr); + break; + } } break; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs index a3ce26eb4f2..12391c49bfe 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs @@ -2084,6 +2084,13 @@ static ImageUpscalingFilter ResolveUpscalingFilterSelection(Vector2 imageSize, f break; } + case UpscalingFilterSelection.SGSR: + { + filter = ImageUpscalingFilter.SGSR; + + break; + } + case UpscalingFilterSelection.STP: { filter = ImageUpscalingFilter.STP; diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipelineCore.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipelineCore.cs index 9a3e14b0fa2..6ff4851d616 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipelineCore.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipelineCore.cs @@ -75,6 +75,9 @@ internal enum ImageUpscalingFilter /// FidelityFX Super Resolution FSR, + /// Snapdragon Game Super Resolution + SGSR, + /// Spatial-Temporal Post-Processing STP } @@ -1301,6 +1304,9 @@ public static class ShaderKeywordStrings /// Keyword used for Robust Contrast-Adaptive Sharpening (RCAS) when doing upsampling, after EASU has ran and with HDR Dsiplay output. public const string EasuRcasAndHDRInput = "_EASU_RCAS_AND_HDR_INPUT"; + /// Keyword used for Snapdragon Game Super Resolution. + public const string Sgsr = "_SGSR"; + /// Keyword used for Gamma 2.0. public const string Gamma20 = "_GAMMA_20"; diff --git a/Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/FinalPost.shader b/Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/FinalPost.shader index c7f4b7a22df..64f77656925 100644 --- a/Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/FinalPost.shader +++ b/Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/FinalPost.shader @@ -1,7 +1,7 @@ Shader "Hidden/Universal Render Pipeline/FinalPost" { HLSLINCLUDE - #pragma multi_compile_local_fragment _ _POINT_SAMPLING _RCAS _EASU_RCAS_AND_HDR_INPUT + #pragma multi_compile_local_fragment _ _POINT_SAMPLING _RCAS _EASU_RCAS_AND_HDR_INPUT _SGSR #pragma multi_compile_local_fragment _ _FXAA #pragma multi_compile_local_fragment _ _FILM_GRAIN #pragma multi_compile_local_fragment _ _DITHERING @@ -55,6 +55,49 @@ Shader "Hidden/Universal Render Pipeline/FinalPost" #include "Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/FSRCommon.hlsl" #endif + #if defined(_SGSR) + #define SGSR_MOBILE + + half4 SGSRRH(float2 p) + { + half4 res = _BlitTexture.GatherRed(sampler_LinearClamp, p); + return res; + } + half4 SGSRGH(float2 p) + { + half4 res = _BlitTexture.GatherGreen(sampler_LinearClamp, p); + return res; + } + half4 SGSRBH(float2 p) + { + half4 res = _BlitTexture.GatherBlue(sampler_LinearClamp, p); + return res; + } + half4 SGSRAH(float2 p) + { + half4 res = _BlitTexture.GatherAlpha(sampler_LinearClamp, p); + return res; + } + half4 SGSRRGBH(float2 p) + { + half4 res = _BlitTexture.SampleLevel(sampler_LinearClamp, p, 0); + return res; + } + + half4 SGSRH(float2 p, uint channel) + { + if (channel == 0) + return SGSRRH(p); + if (channel == 1) + return SGSRGH(p); + if (channel == 2) + return SGSRBH(p); + return SGSRAH(p); + } + + #include "Packages/com.unity.render-pipelines.core/Runtime/PostProcessing/Shaders/sgsr/sgsr_mobile.hlsl" + #endif + half4 FragFinalPost(Varyings input) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); @@ -80,6 +123,13 @@ Shader "Hidden/Universal Render Pipeline/FinalPost" #if _ENABLE_ALPHA_OUTPUT color.a = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, uv).a; #endif + #elif _SGSR + half4 color = half4(0, 0, 0, 1); + // ViewportInfo should be a float4 containing {1.0/low_res_tex_width, 1.0/low_res_tex_height, low_res_tex_width, low_res_tex_height}. + // The `xy` components will be used to shift UVs to read adjacent texels. + // The `zw` components will be used to map from UV space [0, 1][0, 1] to image space [0, w][0, h]. + // _SourceSize contains the same data as ViewportInfo except xy are swapped with zw + SgsrYuvH(color, uv, _SourceSize.zwxy); #else half4 color = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, uv); #endif