Browse Source
Added ASR runtime source files, as a copy of the FSR2 sources, with a bunch of renaming and stripped of some parts that we know we're not going to need.
asr-console
Added ASR runtime source files, as a copy of the FSR2 sources, with a bunch of renaming and stripped of some parts that we know we're not going to need.
asr-console
17 changed files with 1887 additions and 0 deletions
-
8Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime.meta
-
292Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/Asr.cs
-
11Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/Asr.cs.meta
-
152Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrAssets.cs
-
11Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrAssets.cs.meta
-
81Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrCallbacks.cs
-
11Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrCallbacks.cs.meta
-
570Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrContext.cs
-
11Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrContext.cs.meta
-
339Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrPass.cs
-
11Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrPass.cs.meta
-
227Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrResources.cs
-
11Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrResources.cs.meta
-
75Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrShaderIDs.cs
-
11Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrShaderIDs.cs.meta
-
55Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/ResourceView.cs
-
11Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/ResourceView.cs.meta
@ -0,0 +1,8 @@ |
|||||
|
fileFormatVersion: 2 |
||||
|
guid: 6bbfbdd9fd482bd4ea5e998953ae9972 |
||||
|
folderAsset: yes |
||||
|
DefaultImporter: |
||||
|
externalObjects: {} |
||||
|
userData: |
||||
|
assetBundleName: |
||||
|
assetBundleVariant: |
||||
@ -0,0 +1,292 @@ |
|||||
|
// Copyright (c) 2024 Nico de Poel
|
||||
|
//
|
||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
// in the Software without restriction, including without limitation the rights
|
||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||
|
// furnished to do so, subject to the following conditions:
|
||||
|
//
|
||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||
|
// copies or substantial portions of the Software.
|
||||
|
//
|
||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
|
// THE SOFTWARE.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using UnityEngine; |
||||
|
|
||||
|
namespace ArmASR |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A collection of helper functions and data structures required by the ASR process.
|
||||
|
/// </summary>
|
||||
|
public static class Asr |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Creates a new ASR context with standard parameters that are appropriate for the current platform.
|
||||
|
/// </summary>
|
||||
|
public static AsrContext CreateContext(Vector2Int displaySize, Vector2Int maxRenderSize, AsrShaders shaders, InitializationFlags flags = 0) |
||||
|
{ |
||||
|
if (SystemInfo.usesReversedZBuffer) |
||||
|
flags |= InitializationFlags.EnableDepthInverted; |
||||
|
else |
||||
|
flags &= ~InitializationFlags.EnableDepthInverted; |
||||
|
|
||||
|
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
|
flags |= InitializationFlags.EnableDebugChecking; |
||||
|
#endif
|
||||
|
|
||||
|
Debug.Log($"Setting up Arm ASR with render size: {maxRenderSize.x}x{maxRenderSize.y}, display size: {displaySize.x}x{displaySize.y}, flags: {flags}"); |
||||
|
|
||||
|
var contextDescription = new ContextDescription |
||||
|
{ |
||||
|
Flags = flags, |
||||
|
DisplaySize = displaySize, |
||||
|
MaxRenderSize = maxRenderSize, |
||||
|
Shaders = shaders, |
||||
|
}; |
||||
|
|
||||
|
var context = new AsrContext(); |
||||
|
context.Create(contextDescription); |
||||
|
return context; |
||||
|
} |
||||
|
|
||||
|
public static float GetUpscaleRatioFromQualityMode(QualityMode qualityMode) |
||||
|
{ |
||||
|
switch (qualityMode) |
||||
|
{ |
||||
|
case QualityMode.NativeAA: |
||||
|
return 1.0f; |
||||
|
case QualityMode.UltraQuality: |
||||
|
return 1.2f; |
||||
|
case QualityMode.Quality: |
||||
|
return 1.5f; |
||||
|
case QualityMode.Balanced: |
||||
|
return 1.7f; |
||||
|
case QualityMode.Performance: |
||||
|
return 2.0f; |
||||
|
case QualityMode.UltraPerformance: |
||||
|
return 3.0f; |
||||
|
default: |
||||
|
return 1.0f; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static void GetRenderResolutionFromQualityMode( |
||||
|
out int renderWidth, out int renderHeight, |
||||
|
int displayWidth, int displayHeight, QualityMode qualityMode) |
||||
|
{ |
||||
|
float ratio = GetUpscaleRatioFromQualityMode(qualityMode); |
||||
|
renderWidth = Mathf.RoundToInt(displayWidth / ratio); |
||||
|
renderHeight = Mathf.RoundToInt(displayHeight / ratio); |
||||
|
} |
||||
|
|
||||
|
public static float GetMipmapBiasOffset(int renderWidth, int displayWidth) |
||||
|
{ |
||||
|
return Mathf.Log((float)renderWidth / displayWidth, 2.0f) - 1.0f; |
||||
|
} |
||||
|
|
||||
|
public static int GetJitterPhaseCount(int renderWidth, int displayWidth) |
||||
|
{ |
||||
|
const float basePhaseCount = 8.0f; |
||||
|
int jitterPhaseCount = (int)(basePhaseCount * Mathf.Pow((float)displayWidth / renderWidth, 2.0f)); |
||||
|
return jitterPhaseCount; |
||||
|
} |
||||
|
|
||||
|
public static void GetJitterOffset(out float outX, out float outY, int index, int phaseCount) |
||||
|
{ |
||||
|
outX = Halton((index % phaseCount) + 1, 2) - 0.5f; |
||||
|
outY = Halton((index % phaseCount) + 1, 3) - 0.5f; |
||||
|
} |
||||
|
|
||||
|
// Calculate halton number for index and base.
|
||||
|
private static float Halton(int index, int @base) |
||||
|
{ |
||||
|
float f = 1.0f, result = 0.0f; |
||||
|
|
||||
|
for (int currentIndex = index; currentIndex > 0;) { |
||||
|
|
||||
|
f /= @base; |
||||
|
result += f * (currentIndex % @base); |
||||
|
currentIndex = (int)Mathf.Floor((float)currentIndex / @base); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public static float Lanczos2(float value) |
||||
|
{ |
||||
|
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)); |
||||
|
} |
||||
|
|
||||
|
#if !UNITY_2021_1_OR_NEWER
|
||||
|
internal static void SetBufferData(this CommandBuffer commandBuffer, ComputeBuffer computeBuffer, Array data) |
||||
|
{ |
||||
|
commandBuffer.SetComputeBufferData(computeBuffer, data); |
||||
|
} |
||||
|
#endif
|
||||
|
|
||||
|
public enum QualityMode |
||||
|
{ |
||||
|
NativeAA = 0, |
||||
|
UltraQuality = 1, |
||||
|
Quality = 2, |
||||
|
Balanced = 3, |
||||
|
Performance = 4, |
||||
|
UltraPerformance = 5, |
||||
|
} |
||||
|
|
||||
|
[Flags] |
||||
|
public enum InitializationFlags |
||||
|
{ |
||||
|
EnableHighDynamicRange = 1 << 0, |
||||
|
EnableDisplayResolutionMotionVectors = 1 << 1, |
||||
|
EnableMotionVectorsJitterCancellation = 1 << 2, |
||||
|
EnableDepthInverted = 1 << 3, |
||||
|
EnableDepthInfinite = 1 << 4, |
||||
|
EnableAutoExposure = 1 << 5, |
||||
|
EnableDynamicResolution = 1 << 6, |
||||
|
EnableFP16Usage = 1 << 7, |
||||
|
EnableDebugChecking = 1 << 8, |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A structure encapsulating the parameters required to initialize FidelityFX Super Resolution 2 upscaling.
|
||||
|
/// </summary>
|
||||
|
public struct ContextDescription |
||||
|
{ |
||||
|
public InitializationFlags Flags; |
||||
|
public Vector2Int MaxRenderSize; |
||||
|
public Vector2Int DisplaySize; |
||||
|
public AsrShaders Shaders; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A structure encapsulating the parameters for dispatching the various passes of FidelityFX Super Resolution 2.
|
||||
|
/// </summary>
|
||||
|
public class DispatchDescription |
||||
|
{ |
||||
|
public ResourceView Color; |
||||
|
public ResourceView Depth; |
||||
|
public ResourceView MotionVectors; |
||||
|
public ResourceView Exposure; // optional
|
||||
|
public ResourceView Reactive; // optional
|
||||
|
public ResourceView TransparencyAndComposition; // optional
|
||||
|
public ResourceView Output; |
||||
|
public Vector2 JitterOffset; |
||||
|
public Vector2 MotionVectorScale; |
||||
|
public Vector2Int RenderSize; |
||||
|
public Vector2Int InputResourceSize; |
||||
|
public bool EnableSharpening; |
||||
|
public float Sharpness; |
||||
|
public float FrameTimeDelta; // in seconds
|
||||
|
public float PreExposure; |
||||
|
public bool Reset; |
||||
|
public float CameraNear; |
||||
|
public float CameraFar; |
||||
|
public float CameraFovAngleVertical; |
||||
|
public float ViewSpaceToMetersFactor; |
||||
|
public bool UseTextureArrays; // Enable texture array bindings, primarily used for HDRP and XR
|
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// A structure encapsulating the parameters for automatic generation of a reactive mask.
|
||||
|
/// </summary>
|
||||
|
public class GenerateReactiveDescription |
||||
|
{ |
||||
|
public ResourceView ColorOpaqueOnly; |
||||
|
public ResourceView ColorPreUpscale; |
||||
|
public ResourceView OutReactive; |
||||
|
public Vector2Int RenderSize; |
||||
|
public float Scale = 0.5f; |
||||
|
public float CutoffThreshold = 0.2f; |
||||
|
public float BinaryValue = 0.9f; |
||||
|
public GenerateReactiveFlags Flags = GenerateReactiveFlags.ApplyTonemap | GenerateReactiveFlags.ApplyThreshold | GenerateReactiveFlags.UseComponentsMax; |
||||
|
} |
||||
|
|
||||
|
[Flags] |
||||
|
public enum GenerateReactiveFlags |
||||
|
{ |
||||
|
ApplyTonemap = 1 << 0, |
||||
|
ApplyInverseTonemap = 1 << 1, |
||||
|
ApplyThreshold = 1 << 2, |
||||
|
UseComponentsMax = 1 << 3, |
||||
|
} |
||||
|
|
||||
|
[Serializable, StructLayout(LayoutKind.Sequential)] |
||||
|
internal struct UpscalerConstants |
||||
|
{ |
||||
|
public Vector2Int renderSize; |
||||
|
public Vector2Int maxRenderSize; |
||||
|
public Vector2Int displaySize; |
||||
|
public Vector2Int inputColorResourceDimensions; |
||||
|
public Vector2Int lumaMipDimensions; |
||||
|
public int lumaMipLevelToUse; |
||||
|
public int frameIndex; |
||||
|
|
||||
|
public Vector4 deviceToViewDepth; |
||||
|
public Vector2 jitterOffset; |
||||
|
public Vector2 motionVectorScale; |
||||
|
public Vector2 downscaleFactor; |
||||
|
public Vector2 motionVectorJitterCancellation; |
||||
|
public float preExposure; |
||||
|
public float previousFramePreExposure; |
||||
|
public float tanHalfFOV; |
||||
|
public float jitterPhaseCount; |
||||
|
public float deltaTime; |
||||
|
public float dynamicResChangeFactor; |
||||
|
public float viewSpaceToMetersFactor; |
||||
|
public float padding; |
||||
|
} |
||||
|
|
||||
|
[Serializable, StructLayout(LayoutKind.Sequential)] |
||||
|
internal struct SpdConstants |
||||
|
{ |
||||
|
public uint mips; |
||||
|
public uint numWorkGroups; |
||||
|
public uint workGroupOffsetX, workGroupOffsetY; |
||||
|
public uint renderSizeX, renderSizeY; |
||||
|
} |
||||
|
|
||||
|
[Serializable, StructLayout(LayoutKind.Sequential)] |
||||
|
internal struct GenerateReactiveConstants |
||||
|
{ |
||||
|
public float scale; |
||||
|
public float threshold; |
||||
|
public float binaryValue; |
||||
|
public uint flags; |
||||
|
} |
||||
|
|
||||
|
[Serializable, StructLayout(LayoutKind.Sequential)] |
||||
|
internal struct GenerateReactiveConstants2 |
||||
|
{ |
||||
|
public float autoTcThreshold; |
||||
|
public float autoTcScale; |
||||
|
public float autoReactiveScale; |
||||
|
public float autoReactiveMax; |
||||
|
} |
||||
|
|
||||
|
[Serializable, StructLayout(LayoutKind.Sequential)] |
||||
|
internal struct RcasConstants |
||||
|
{ |
||||
|
public RcasConstants(uint sharpness, uint halfSharp) |
||||
|
{ |
||||
|
this.sharpness = sharpness; |
||||
|
this.halfSharp = halfSharp; |
||||
|
dummy0 = dummy1 = 0; |
||||
|
} |
||||
|
|
||||
|
public readonly uint sharpness; |
||||
|
public readonly uint halfSharp; |
||||
|
public readonly uint dummy0; |
||||
|
public readonly uint dummy1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
fileFormatVersion: 2 |
||||
|
guid: c7350363c6d8a2b4096a9ed97dc4ed95 |
||||
|
MonoImporter: |
||||
|
externalObjects: {} |
||||
|
serializedVersion: 2 |
||||
|
defaultReferences: [] |
||||
|
executionOrder: 0 |
||||
|
icon: {instanceID: 0} |
||||
|
userData: |
||||
|
assetBundleName: |
||||
|
assetBundleVariant: |
||||
@ -0,0 +1,152 @@ |
|||||
|
// Copyright (c) 2024 Nico de Poel
|
||||
|
//
|
||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
// in the Software without restriction, including without limitation the rights
|
||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||
|
// furnished to do so, subject to the following conditions:
|
||||
|
//
|
||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||
|
// copies or substantial portions of the Software.
|
||||
|
//
|
||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
|
// THE SOFTWARE.
|
||||
|
|
||||
|
using UnityEngine; |
||||
|
|
||||
|
namespace ArmASR |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Scriptable object containing all shader resources required by Arm Accuracy Super Resolution (ASR).
|
||||
|
/// These can be stored in an asset file and referenced from a scene or prefab, avoiding the need to load the shaders from a Resources folder.
|
||||
|
/// </summary>
|
||||
|
[CreateAssetMenu(fileName = "ASR Assets", menuName = "ARM/ASR Assets", order = 1102)] |
||||
|
public class AsrAssets : ScriptableObject |
||||
|
{ |
||||
|
public AsrShaders shaders; |
||||
|
|
||||
|
#if UNITY_EDITOR
|
||||
|
private void Reset() |
||||
|
{ |
||||
|
shaders = new AsrShaders |
||||
|
{ |
||||
|
computeLuminancePyramidPass = FindComputeShader("ffxm_fsr2_compute_luminance_pyramid_pass"), |
||||
|
reconstructPreviousDepthPass = FindComputeShader("ffx_fsr2_reconstruct_previous_depth_pass"), |
||||
|
depthClipPass = FindComputeShader("ffx_fsr2_depth_clip_pass"), |
||||
|
lockPass = FindComputeShader("ffxm_fsr2_lock_pass"), |
||||
|
accumulatePass = FindComputeShader("ffx_fsr2_accumulate_pass"), |
||||
|
sharpenPass = FindComputeShader("ffx_fsr2_rcas_pass"), |
||||
|
autoGenReactivePass = FindComputeShader("ffx_fsr2_autogen_reactive_pass"), |
||||
|
tcrAutoGenPass = FindComputeShader("ffx_fsr2_tcr_autogen_pass"), |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
private static ComputeShader FindComputeShader(string name) |
||||
|
{ |
||||
|
string[] assetGuids = UnityEditor.AssetDatabase.FindAssets($"t:ComputeShader {name}"); |
||||
|
if (assetGuids == null || assetGuids.Length == 0) |
||||
|
return null; |
||||
|
|
||||
|
string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(assetGuids[0]); |
||||
|
return UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(assetPath); |
||||
|
} |
||||
|
#endif
|
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// All the compute shaders used by ASR.
|
||||
|
/// </summary>
|
||||
|
[System.Serializable] |
||||
|
public class AsrShaders |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The compute shader used by the luminance pyramid computation pass.
|
||||
|
/// </summary>
|
||||
|
public ComputeShader computeLuminancePyramidPass; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The compute shader used by the previous depth reconstruction pass.
|
||||
|
/// </summary>
|
||||
|
public ComputeShader reconstructPreviousDepthPass; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The compute shader used by the depth clip pass.
|
||||
|
/// </summary>
|
||||
|
public ComputeShader depthClipPass; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The compute shader used by the lock pass.
|
||||
|
/// </summary>
|
||||
|
public ComputeShader lockPass; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The compute shader used by the accumulation pass.
|
||||
|
/// </summary>
|
||||
|
public ComputeShader accumulatePass; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The compute shader used by the RCAS sharpening pass.
|
||||
|
/// </summary>
|
||||
|
public ComputeShader sharpenPass; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The compute shader used to auto-generate a reactive mask.
|
||||
|
/// </summary>
|
||||
|
public ComputeShader autoGenReactivePass; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The compute shader used to auto-generate a transparency & composition mask.
|
||||
|
/// </summary>
|
||||
|
public ComputeShader tcrAutoGenPass; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns a copy of this class and its contents.
|
||||
|
/// </summary>
|
||||
|
public AsrShaders Clone() |
||||
|
{ |
||||
|
return (AsrShaders)MemberwiseClone(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns a copy of this class with clones of all its shaders.
|
||||
|
/// This can be useful if you're running multiple ASR instances with different shader configurations.
|
||||
|
/// Be sure to clean up these clones through Dispose once you're done with them.
|
||||
|
/// </summary>
|
||||
|
public AsrShaders DeepCopy() |
||||
|
{ |
||||
|
return new AsrShaders |
||||
|
{ |
||||
|
computeLuminancePyramidPass = Object.Instantiate(computeLuminancePyramidPass), |
||||
|
reconstructPreviousDepthPass = Object.Instantiate(reconstructPreviousDepthPass), |
||||
|
depthClipPass = Object.Instantiate(depthClipPass), |
||||
|
lockPass = Object.Instantiate(lockPass), |
||||
|
accumulatePass = Object.Instantiate(accumulatePass), |
||||
|
sharpenPass = Object.Instantiate(sharpenPass), |
||||
|
autoGenReactivePass = Object.Instantiate(autoGenReactivePass), |
||||
|
tcrAutoGenPass = Object.Instantiate(tcrAutoGenPass), |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Destroy all the shaders within this instance.
|
||||
|
/// Use this only on clones created through DeepCopy.
|
||||
|
/// </summary>
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
Object.Destroy(computeLuminancePyramidPass); |
||||
|
Object.Destroy(reconstructPreviousDepthPass); |
||||
|
Object.Destroy(depthClipPass); |
||||
|
Object.Destroy(lockPass); |
||||
|
Object.Destroy(accumulatePass); |
||||
|
Object.Destroy(sharpenPass); |
||||
|
Object.Destroy(autoGenReactivePass); |
||||
|
Object.Destroy(tcrAutoGenPass); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
fileFormatVersion: 2 |
||||
|
guid: 7a41695239eb36740847744b34c5af43 |
||||
|
MonoImporter: |
||||
|
externalObjects: {} |
||||
|
serializedVersion: 2 |
||||
|
defaultReferences: [] |
||||
|
executionOrder: 0 |
||||
|
icon: {instanceID: 0} |
||||
|
userData: |
||||
|
assetBundleName: |
||||
|
assetBundleVariant: |
||||
@ -0,0 +1,81 @@ |
|||||
|
// Copyright (c) 2024 Nico de Poel
|
||||
|
//
|
||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
// in the Software without restriction, including without limitation the rights
|
||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||
|
// furnished to do so, subject to the following conditions:
|
||||
|
//
|
||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||
|
// copies or substantial portions of the Software.
|
||||
|
//
|
||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
|
// THE SOFTWARE.
|
||||
|
|
||||
|
using UnityEngine; |
||||
|
|
||||
|
namespace ArmASR |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A collection of callbacks required by the ASR process.
|
||||
|
/// This allows some customization by the game dev on how to integrate ASR upscaling into their own game setup.
|
||||
|
/// </summary>
|
||||
|
public interface IAsrCallbacks |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Apply a mipmap bias to in-game textures to prevent them from becoming blurry as the internal rendering resolution lowers.
|
||||
|
/// This will need to be customized on a per-game basis, as there is no clear universal way to determine what are "in-game" textures.
|
||||
|
/// The default implementation will simply apply a mipmap bias to all 2D textures, which will include things like UI textures and which might miss things like terrain texture arrays.
|
||||
|
///
|
||||
|
/// Depending on how your game organizes its assets, you will want to create a filter that more specifically selects the textures that need to have this mipmap bias applied.
|
||||
|
/// You may also want to store the bias offset value and apply it to any assets that are loaded in on demand.
|
||||
|
/// </summary>
|
||||
|
void ApplyMipmapBias(float biasOffset); |
||||
|
|
||||
|
void UndoMipmapBias(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Default implementation of IAsrCallbacks.
|
||||
|
/// These are fine for testing but a proper game will want to extend and override these methods.
|
||||
|
/// </summary>
|
||||
|
public class AsrCallbacksBase: IAsrCallbacks |
||||
|
{ |
||||
|
protected float CurrentBiasOffset = 0; |
||||
|
|
||||
|
public virtual void ApplyMipmapBias(float biasOffset) |
||||
|
{ |
||||
|
if (float.IsNaN(biasOffset) || float.IsInfinity(biasOffset)) |
||||
|
return; |
||||
|
|
||||
|
CurrentBiasOffset += biasOffset; |
||||
|
|
||||
|
if (Mathf.Approximately(CurrentBiasOffset, 0f)) |
||||
|
{ |
||||
|
CurrentBiasOffset = 0f; |
||||
|
} |
||||
|
|
||||
|
foreach (var texture in Resources.FindObjectsOfTypeAll<Texture2D>()) |
||||
|
{ |
||||
|
if (texture.mipmapCount <= 1) |
||||
|
continue; |
||||
|
|
||||
|
texture.mipMapBias += biasOffset; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public virtual void UndoMipmapBias() |
||||
|
{ |
||||
|
if (CurrentBiasOffset == 0f) |
||||
|
return; |
||||
|
|
||||
|
ApplyMipmapBias(-CurrentBiasOffset); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
fileFormatVersion: 2 |
||||
|
guid: 78f16fcb80e6325429dfa567a4ed5d4a |
||||
|
MonoImporter: |
||||
|
externalObjects: {} |
||||
|
serializedVersion: 2 |
||||
|
defaultReferences: [] |
||||
|
executionOrder: 0 |
||||
|
icon: {instanceID: 0} |
||||
|
userData: |
||||
|
assetBundleName: |
||||
|
assetBundleVariant: |
||||
@ -0,0 +1,570 @@ |
|||||
|
// Copyright (c) 2024 Nico de Poel
|
||||
|
//
|
||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
// in the Software without restriction, including without limitation the rights
|
||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||
|
// furnished to do so, subject to the following conditions:
|
||||
|
//
|
||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||
|
// copies or substantial portions of the Software.
|
||||
|
//
|
||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
|
// THE SOFTWARE.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Runtime.InteropServices; |
||||
|
using UnityEngine; |
||||
|
using UnityEngine.Rendering; |
||||
|
|
||||
|
namespace ArmASR |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// This class loosely matches the FfxFsr2Context struct from the original FSR2 codebase.
|
||||
|
/// It manages the various resources and compute passes required by the ASR process.
|
||||
|
/// Note that this class does not know anything about Unity render pipelines; all it knows is CommandBuffers and RenderTargetIdentifiers.
|
||||
|
/// This should make it suitable for integration with any of the available Unity render pipelines.
|
||||
|
/// </summary>
|
||||
|
public class AsrContext |
||||
|
{ |
||||
|
private const int MaxQueuedFrames = 16; |
||||
|
|
||||
|
private Asr.ContextDescription _contextDescription; |
||||
|
private CommandBuffer _commandBuffer; |
||||
|
|
||||
|
private AsrPass _computeLuminancePyramidPass; |
||||
|
private AsrPass _reconstructPreviousDepthPass; |
||||
|
private AsrPass _depthClipPass; |
||||
|
private AsrPass _lockPass; |
||||
|
private AsrPass _accumulatePass; |
||||
|
private AsrPass _sharpenPass; |
||||
|
private AsrPass _generateReactivePass; |
||||
|
private AsrPass _tcrAutogeneratePass; |
||||
|
|
||||
|
private readonly AsrResources _resources = new AsrResources(); |
||||
|
|
||||
|
private ComputeBuffer _upscalerConstantsBuffer; |
||||
|
private readonly Asr.UpscalerConstants[] _upscalerConstantsArray = { new Asr.UpscalerConstants() }; |
||||
|
private ref Asr.UpscalerConstants UpscalerConsts => ref _upscalerConstantsArray[0]; |
||||
|
|
||||
|
private ComputeBuffer _spdConstantsBuffer; |
||||
|
private readonly Asr.SpdConstants[] _spdConstantsArray = { new Asr.SpdConstants() }; |
||||
|
private ref Asr.SpdConstants SpdConsts => ref _spdConstantsArray[0]; |
||||
|
|
||||
|
private ComputeBuffer _rcasConstantsBuffer; |
||||
|
private readonly Asr.RcasConstants[] _rcasConstantsArray = new Asr.RcasConstants[1]; |
||||
|
private ref Asr.RcasConstants RcasConsts => ref _rcasConstantsArray[0]; |
||||
|
|
||||
|
private ComputeBuffer _generateReactiveConstantsBuffer; |
||||
|
private readonly Asr.GenerateReactiveConstants[] _generateReactiveConstantsArray = { new Asr.GenerateReactiveConstants() }; |
||||
|
private ref Asr.GenerateReactiveConstants GenReactiveConsts => ref _generateReactiveConstantsArray[0]; |
||||
|
|
||||
|
private bool _firstExecution; |
||||
|
private Vector2 _previousJitterOffset; |
||||
|
private int _resourceFrameIndex; |
||||
|
|
||||
|
public void Create(Asr.ContextDescription contextDescription) |
||||
|
{ |
||||
|
_contextDescription = contextDescription; |
||||
|
_commandBuffer = new CommandBuffer { name = "Arm ASR" }; |
||||
|
|
||||
|
_upscalerConstantsBuffer = CreateConstantBuffer<Asr.UpscalerConstants>(); |
||||
|
_spdConstantsBuffer = CreateConstantBuffer<Asr.SpdConstants>(); |
||||
|
_rcasConstantsBuffer = CreateConstantBuffer<Asr.RcasConstants>(); |
||||
|
_generateReactiveConstantsBuffer = CreateConstantBuffer<Asr.GenerateReactiveConstants>(); |
||||
|
|
||||
|
// Set defaults
|
||||
|
_firstExecution = true; |
||||
|
_resourceFrameIndex = 0; |
||||
|
|
||||
|
UpscalerConsts.displaySize = _contextDescription.DisplaySize; |
||||
|
|
||||
|
_resources.Create(_contextDescription); |
||||
|
CreatePasses(); |
||||
|
} |
||||
|
|
||||
|
private void CreatePasses() |
||||
|
{ |
||||
|
_computeLuminancePyramidPass = new AsrComputeLuminancePyramidPass(_contextDescription, _resources, _upscalerConstantsBuffer, _spdConstantsBuffer); |
||||
|
_reconstructPreviousDepthPass = new AsrReconstructPreviousDepthPass(_contextDescription, _resources, _upscalerConstantsBuffer); |
||||
|
_depthClipPass = new AsrDepthClipPass(_contextDescription, _resources, _upscalerConstantsBuffer); |
||||
|
_lockPass = new AsrLockPass(_contextDescription, _resources, _upscalerConstantsBuffer); |
||||
|
_accumulatePass = new AsrAccumulatePass(_contextDescription, _resources, _upscalerConstantsBuffer); |
||||
|
_sharpenPass = new AsrSharpenPass(_contextDescription, _resources, _upscalerConstantsBuffer, _rcasConstantsBuffer); |
||||
|
_generateReactivePass = new AsrGenerateReactivePass(_contextDescription, _resources, _generateReactiveConstantsBuffer); |
||||
|
} |
||||
|
|
||||
|
public void Destroy() |
||||
|
{ |
||||
|
DestroyPass(ref _tcrAutogeneratePass); |
||||
|
DestroyPass(ref _generateReactivePass); |
||||
|
DestroyPass(ref _sharpenPass); |
||||
|
DestroyPass(ref _accumulatePass); |
||||
|
DestroyPass(ref _lockPass); |
||||
|
DestroyPass(ref _depthClipPass); |
||||
|
DestroyPass(ref _reconstructPreviousDepthPass); |
||||
|
DestroyPass(ref _computeLuminancePyramidPass); |
||||
|
|
||||
|
_resources.Destroy(); |
||||
|
|
||||
|
DestroyConstantBuffer(ref _generateReactiveConstantsBuffer); |
||||
|
DestroyConstantBuffer(ref _rcasConstantsBuffer); |
||||
|
DestroyConstantBuffer(ref _spdConstantsBuffer); |
||||
|
DestroyConstantBuffer(ref _upscalerConstantsBuffer); |
||||
|
|
||||
|
if (_commandBuffer != null) |
||||
|
{ |
||||
|
_commandBuffer.Dispose(); |
||||
|
_commandBuffer = null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void Dispatch(Asr.DispatchDescription dispatchParams) |
||||
|
{ |
||||
|
_commandBuffer.Clear(); |
||||
|
Dispatch(dispatchParams, _commandBuffer); |
||||
|
Graphics.ExecuteCommandBuffer(_commandBuffer); |
||||
|
} |
||||
|
|
||||
|
public void Dispatch(Asr.DispatchDescription dispatchParams, CommandBuffer commandBuffer) |
||||
|
{ |
||||
|
if ((_contextDescription.Flags & Asr.InitializationFlags.EnableDebugChecking) != 0) |
||||
|
{ |
||||
|
DebugCheckDispatch(dispatchParams); |
||||
|
} |
||||
|
|
||||
|
if (dispatchParams.UseTextureArrays) |
||||
|
commandBuffer.EnableShaderKeyword("UNITY_FFXM_TEXTURE2D_X_ARRAY"); |
||||
|
|
||||
|
if (_firstExecution) |
||||
|
{ |
||||
|
commandBuffer.SetRenderTarget(_resources.LockStatus[0]); |
||||
|
commandBuffer.ClearRenderTarget(false, true, Color.clear); |
||||
|
commandBuffer.SetRenderTarget(_resources.LockStatus[1]); |
||||
|
commandBuffer.ClearRenderTarget(false, true, Color.clear); |
||||
|
} |
||||
|
|
||||
|
int frameIndex = _resourceFrameIndex % 2; |
||||
|
bool resetAccumulation = dispatchParams.Reset || _firstExecution; |
||||
|
_firstExecution = false; |
||||
|
|
||||
|
// If auto exposure is enabled use the auto exposure SRV, otherwise what the app sends
|
||||
|
if ((_contextDescription.Flags & Asr.InitializationFlags.EnableAutoExposure) != 0) |
||||
|
dispatchParams.Exposure = new ResourceView(_resources.AutoExposure); |
||||
|
else if (!dispatchParams.Exposure.IsValid) |
||||
|
dispatchParams.Exposure = new ResourceView(_resources.DefaultExposure); |
||||
|
|
||||
|
if (!dispatchParams.Reactive.IsValid) dispatchParams.Reactive = new ResourceView(_resources.DefaultReactive); |
||||
|
if (!dispatchParams.TransparencyAndComposition.IsValid) dispatchParams.TransparencyAndComposition = new ResourceView(_resources.DefaultReactive); |
||||
|
AsrResources.CreateAliasableResources(commandBuffer, _contextDescription, dispatchParams); |
||||
|
|
||||
|
SetupConstants(dispatchParams, resetAccumulation); |
||||
|
|
||||
|
// Reactive mask bias
|
||||
|
const int threadGroupWorkRegionDim = 8; |
||||
|
int dispatchSrcX = (UpscalerConsts.renderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; |
||||
|
int dispatchSrcY = (UpscalerConsts.renderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; |
||||
|
int dispatchDstX = (_contextDescription.DisplaySize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; |
||||
|
int dispatchDstY = (_contextDescription.DisplaySize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; |
||||
|
|
||||
|
// Clear reconstructed depth for max depth store
|
||||
|
if (resetAccumulation) |
||||
|
{ |
||||
|
commandBuffer.SetRenderTarget(_resources.LockStatus[frameIndex ^ 1]); |
||||
|
commandBuffer.ClearRenderTarget(false, true, Color.clear); |
||||
|
|
||||
|
commandBuffer.SetRenderTarget(_resources.InternalUpscaled[frameIndex ^ 1]); |
||||
|
commandBuffer.ClearRenderTarget(false, true, Color.clear); |
||||
|
|
||||
|
commandBuffer.SetRenderTarget(_resources.SceneLuminance); |
||||
|
commandBuffer.ClearRenderTarget(false, true, Color.clear); |
||||
|
|
||||
|
// Auto exposure always used to track luma changes in locking logic
|
||||
|
commandBuffer.SetRenderTarget(_resources.AutoExposure); |
||||
|
commandBuffer.ClearRenderTarget(false, true, new Color(0f, 1e8f, 0f, 0f)); |
||||
|
|
||||
|
// Reset atomic counter to 0
|
||||
|
commandBuffer.SetRenderTarget(_resources.SpdAtomicCounter); |
||||
|
commandBuffer.ClearRenderTarget(false, true, Color.clear); |
||||
|
} |
||||
|
|
||||
|
// FSR3: need to clear here since we need the content of this surface for frame interpolation, so clearing in the lock pass is not an option
|
||||
|
bool depthInverted = (_contextDescription.Flags & Asr.InitializationFlags.EnableDepthInverted) == Asr.InitializationFlags.EnableDepthInverted; |
||||
|
commandBuffer.SetRenderTarget(AsrShaderIDs.UavReconstructedPrevNearestDepth); |
||||
|
commandBuffer.ClearRenderTarget(false, true, depthInverted ? Color.clear : Color.white); |
||||
|
|
||||
|
// Auto exposure
|
||||
|
SetupSpdConstants(dispatchParams, out var dispatchThreadGroupCount); |
||||
|
|
||||
|
// Initialize constant buffers data
|
||||
|
commandBuffer.SetBufferData(_upscalerConstantsBuffer, _upscalerConstantsArray); |
||||
|
commandBuffer.SetBufferData(_spdConstantsBuffer, _spdConstantsArray); |
||||
|
|
||||
|
// Compute luminance pyramid
|
||||
|
_computeLuminancePyramidPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y); |
||||
|
|
||||
|
// Reconstruct previous depth
|
||||
|
_reconstructPreviousDepthPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY); |
||||
|
|
||||
|
// Depth clip
|
||||
|
_depthClipPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY); |
||||
|
|
||||
|
// Create locks
|
||||
|
_lockPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY); |
||||
|
|
||||
|
// Accumulate
|
||||
|
_accumulatePass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchDstX, dispatchDstY); |
||||
|
|
||||
|
if (dispatchParams.EnableSharpening) |
||||
|
{ |
||||
|
// Compute the constants
|
||||
|
SetupRcasConstants(dispatchParams); |
||||
|
commandBuffer.SetBufferData(_rcasConstantsBuffer, _rcasConstantsArray); |
||||
|
|
||||
|
// Dispatch RCAS
|
||||
|
const int threadGroupWorkRegionDimRcas = 16; |
||||
|
int threadGroupsX = (Screen.width + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas; |
||||
|
int threadGroupsY = (Screen.height + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas; |
||||
|
_sharpenPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, threadGroupsX, threadGroupsY); |
||||
|
} |
||||
|
|
||||
|
_resourceFrameIndex = (_resourceFrameIndex + 1) % MaxQueuedFrames; |
||||
|
|
||||
|
AsrResources.DestroyAliasableResources(commandBuffer); |
||||
|
|
||||
|
commandBuffer.DisableShaderKeyword("UNITY_FFXM_TEXTURE2D_X_ARRAY"); |
||||
|
} |
||||
|
|
||||
|
public void GenerateReactiveMask(Asr.GenerateReactiveDescription dispatchParams) |
||||
|
{ |
||||
|
_commandBuffer.Clear(); |
||||
|
GenerateReactiveMask(dispatchParams, _commandBuffer); |
||||
|
Graphics.ExecuteCommandBuffer(_commandBuffer); |
||||
|
} |
||||
|
|
||||
|
public void GenerateReactiveMask(Asr.GenerateReactiveDescription dispatchParams, CommandBuffer commandBuffer) |
||||
|
{ |
||||
|
const int threadGroupWorkRegionDim = 8; |
||||
|
int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; |
||||
|
int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; |
||||
|
|
||||
|
GenReactiveConsts.scale = dispatchParams.Scale; |
||||
|
GenReactiveConsts.threshold = dispatchParams.CutoffThreshold; |
||||
|
GenReactiveConsts.binaryValue = dispatchParams.BinaryValue; |
||||
|
GenReactiveConsts.flags = (uint)dispatchParams.Flags; |
||||
|
commandBuffer.SetBufferData(_generateReactiveConstantsBuffer, _generateReactiveConstantsArray); |
||||
|
|
||||
|
((AsrGenerateReactivePass)_generateReactivePass).ScheduleDispatch(commandBuffer, dispatchParams, dispatchSrcX, dispatchSrcY); |
||||
|
} |
||||
|
|
||||
|
private void SetupConstants(Asr.DispatchDescription dispatchParams, bool resetAccumulation) |
||||
|
{ |
||||
|
ref Asr.UpscalerConstants constants = ref UpscalerConsts; |
||||
|
|
||||
|
constants.jitterOffset = dispatchParams.JitterOffset; |
||||
|
constants.renderSize = dispatchParams.RenderSize; |
||||
|
constants.maxRenderSize = _contextDescription.MaxRenderSize; |
||||
|
constants.inputColorResourceDimensions = dispatchParams.InputResourceSize; |
||||
|
|
||||
|
// Compute the horizontal FOV for the shader from the vertical one
|
||||
|
float aspectRatio = (float)dispatchParams.RenderSize.x / dispatchParams.RenderSize.y; |
||||
|
float cameraAngleHorizontal = Mathf.Atan(Mathf.Tan(dispatchParams.CameraFovAngleVertical / 2.0f) * aspectRatio) * 2.0f; |
||||
|
constants.tanHalfFOV = Mathf.Tan(cameraAngleHorizontal * 0.5f); |
||||
|
constants.viewSpaceToMetersFactor = (dispatchParams.ViewSpaceToMetersFactor > 0.0f) ? dispatchParams.ViewSpaceToMetersFactor : 1.0f; |
||||
|
|
||||
|
// Compute params to enable device depth to view space depth computation in shader
|
||||
|
constants.deviceToViewDepth = SetupDeviceDepthToViewSpaceDepthParams(dispatchParams); |
||||
|
|
||||
|
// To be updated if resource is larger than the actual image size
|
||||
|
constants.downscaleFactor = new Vector2((float)constants.renderSize.x / _contextDescription.DisplaySize.x, (float)constants.renderSize.y / _contextDescription.DisplaySize.y); |
||||
|
constants.previousFramePreExposure = constants.preExposure; |
||||
|
constants.preExposure = (dispatchParams.PreExposure != 0) ? dispatchParams.PreExposure : 1.0f; |
||||
|
|
||||
|
// Motion vector data
|
||||
|
Vector2Int motionVectorsTargetSize = (_contextDescription.Flags & Asr.InitializationFlags.EnableDisplayResolutionMotionVectors) != 0 ? constants.displaySize : constants.renderSize; |
||||
|
constants.motionVectorScale = dispatchParams.MotionVectorScale / motionVectorsTargetSize; |
||||
|
|
||||
|
// Compute jitter cancellation
|
||||
|
if ((_contextDescription.Flags & Asr.InitializationFlags.EnableMotionVectorsJitterCancellation) != 0) |
||||
|
{ |
||||
|
constants.motionVectorJitterCancellation = (_previousJitterOffset - constants.jitterOffset) / motionVectorsTargetSize; |
||||
|
_previousJitterOffset = constants.jitterOffset; |
||||
|
} |
||||
|
|
||||
|
int jitterPhaseCount = Asr.GetJitterPhaseCount(dispatchParams.RenderSize.x, _contextDescription.DisplaySize.x); |
||||
|
if (resetAccumulation || constants.jitterPhaseCount == 0) |
||||
|
{ |
||||
|
constants.jitterPhaseCount = jitterPhaseCount; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
int jitterPhaseCountDelta = (int)(jitterPhaseCount - constants.jitterPhaseCount); |
||||
|
if (jitterPhaseCountDelta > 0) |
||||
|
constants.jitterPhaseCount++; |
||||
|
else if (jitterPhaseCountDelta < 0) |
||||
|
constants.jitterPhaseCount--; |
||||
|
} |
||||
|
|
||||
|
// Convert delta time to seconds and clamp to [0, 1]
|
||||
|
constants.deltaTime = Mathf.Clamp01(dispatchParams.FrameTimeDelta); |
||||
|
|
||||
|
if (resetAccumulation) |
||||
|
constants.frameIndex = 0; |
||||
|
else |
||||
|
constants.frameIndex++; |
||||
|
|
||||
|
// Shading change usage of the SPD mip levels
|
||||
|
constants.lumaMipLevelToUse = AsrPass.ShadingChangeMipLevel; |
||||
|
|
||||
|
float mipDiv = 2 << constants.lumaMipLevelToUse; |
||||
|
constants.lumaMipDimensions.x = (int)(constants.maxRenderSize.x / mipDiv); |
||||
|
constants.lumaMipDimensions.y = (int)(constants.maxRenderSize.y / mipDiv); |
||||
|
} |
||||
|
|
||||
|
private Vector4 SetupDeviceDepthToViewSpaceDepthParams(Asr.DispatchDescription dispatchParams) |
||||
|
{ |
||||
|
bool inverted = (_contextDescription.Flags & Asr.InitializationFlags.EnableDepthInverted) != 0; |
||||
|
bool infinite = (_contextDescription.Flags & Asr.InitializationFlags.EnableDepthInfinite) != 0; |
||||
|
|
||||
|
// make sure it has no impact if near and far plane values are swapped in dispatch params
|
||||
|
// the flags "inverted" and "infinite" will decide what transform to use
|
||||
|
float min = Mathf.Min(dispatchParams.CameraNear, dispatchParams.CameraFar); |
||||
|
float max = Mathf.Max(dispatchParams.CameraNear, dispatchParams.CameraFar); |
||||
|
|
||||
|
if (inverted) |
||||
|
{ |
||||
|
(min, max) = (max, min); |
||||
|
} |
||||
|
|
||||
|
float q = max / (min - max); |
||||
|
float d = -1.0f; |
||||
|
|
||||
|
Vector4 matrixElemC = new Vector4(q, -1.0f - Mathf.Epsilon, q, 0.0f + Mathf.Epsilon); |
||||
|
Vector4 matrixElemE = new Vector4(q * min, -min - Mathf.Epsilon, q * min, max); |
||||
|
|
||||
|
// Revert x and y coords
|
||||
|
float aspect = (float)dispatchParams.RenderSize.x / dispatchParams.RenderSize.y; |
||||
|
float cotHalfFovY = Mathf.Cos(0.5f * dispatchParams.CameraFovAngleVertical) / Mathf.Sin(0.5f * dispatchParams.CameraFovAngleVertical); |
||||
|
|
||||
|
int matrixIndex = (inverted ? 2 : 0) + (infinite ? 1 : 0); |
||||
|
return new Vector4( |
||||
|
d * matrixElemC[matrixIndex], |
||||
|
matrixElemE[matrixIndex], |
||||
|
aspect / cotHalfFovY, |
||||
|
1.0f / cotHalfFovY); |
||||
|
} |
||||
|
|
||||
|
private void SetupRcasConstants(Asr.DispatchDescription dispatchParams) |
||||
|
{ |
||||
|
int sharpnessIndex = Mathf.RoundToInt(Mathf.Clamp01(dispatchParams.Sharpness) * (RcasConfigs.Length - 1)); |
||||
|
RcasConsts = RcasConfigs[sharpnessIndex]; |
||||
|
} |
||||
|
|
||||
|
private void SetupSpdConstants(Asr.DispatchDescription dispatchParams, out Vector2Int dispatchThreadGroupCount) |
||||
|
{ |
||||
|
RectInt rectInfo = new RectInt(0, 0, dispatchParams.RenderSize.x, dispatchParams.RenderSize.y); |
||||
|
SpdSetup(rectInfo, out dispatchThreadGroupCount, out var workGroupOffset, out var numWorkGroupsAndMips); |
||||
|
|
||||
|
// Downsample
|
||||
|
ref Asr.SpdConstants spdConstants = ref SpdConsts; |
||||
|
spdConstants.numWorkGroups = (uint)numWorkGroupsAndMips.x; |
||||
|
spdConstants.mips = (uint)numWorkGroupsAndMips.y; |
||||
|
spdConstants.workGroupOffsetX = (uint)workGroupOffset.x; |
||||
|
spdConstants.workGroupOffsetY = (uint)workGroupOffset.y; |
||||
|
spdConstants.renderSizeX = (uint)dispatchParams.RenderSize.x; |
||||
|
spdConstants.renderSizeY = (uint)dispatchParams.RenderSize.y; |
||||
|
} |
||||
|
|
||||
|
private static void SpdSetup(RectInt rectInfo, out Vector2Int dispatchThreadGroupCount, out Vector2Int workGroupOffset, out Vector2Int numWorkGroupsAndMips, int mips = -1) |
||||
|
{ |
||||
|
workGroupOffset = new Vector2Int(rectInfo.x / 64, rectInfo.y / 64); |
||||
|
|
||||
|
int endIndexX = (rectInfo.x + rectInfo.width - 1) / 64; |
||||
|
int endIndexY = (rectInfo.y + rectInfo.height - 1) / 64; |
||||
|
|
||||
|
dispatchThreadGroupCount = new Vector2Int(endIndexX + 1 - workGroupOffset.x, endIndexY + 1 - workGroupOffset.y); |
||||
|
|
||||
|
numWorkGroupsAndMips = new Vector2Int(dispatchThreadGroupCount.x * dispatchThreadGroupCount.y, mips); |
||||
|
if (mips < 0) |
||||
|
{ |
||||
|
float resolution = Math.Max(rectInfo.width, rectInfo.height); |
||||
|
numWorkGroupsAndMips.y = Math.Min(Mathf.FloorToInt(Mathf.Log(resolution, 2.0f)), 12); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void DebugCheckDispatch(Asr.DispatchDescription dispatchParams) |
||||
|
{ |
||||
|
if (!dispatchParams.Color.IsValid) |
||||
|
{ |
||||
|
Debug.LogError("Color resource is null"); |
||||
|
} |
||||
|
|
||||
|
if (!dispatchParams.Depth.IsValid) |
||||
|
{ |
||||
|
Debug.LogError("Depth resource is null"); |
||||
|
} |
||||
|
|
||||
|
if (!dispatchParams.MotionVectors.IsValid) |
||||
|
{ |
||||
|
Debug.LogError("MotionVectors resource is null"); |
||||
|
} |
||||
|
|
||||
|
if (!dispatchParams.Output.IsValid) |
||||
|
{ |
||||
|
Debug.LogError("Output resource is null"); |
||||
|
} |
||||
|
|
||||
|
if (dispatchParams.Exposure.IsValid && (_contextDescription.Flags & Asr.InitializationFlags.EnableAutoExposure) != 0) |
||||
|
{ |
||||
|
Debug.LogWarning("Exposure resource provided, however auto exposure flag is present"); |
||||
|
} |
||||
|
|
||||
|
if (Mathf.Abs(dispatchParams.JitterOffset.x) > 1.0f || Mathf.Abs(dispatchParams.JitterOffset.y) > 1.0f) |
||||
|
{ |
||||
|
Debug.LogWarning("JitterOffset contains value outside of expected range [-1.0, 1.0]"); |
||||
|
} |
||||
|
|
||||
|
if (dispatchParams.MotionVectorScale.x > _contextDescription.MaxRenderSize.x || dispatchParams.MotionVectorScale.y > _contextDescription.MaxRenderSize.y) |
||||
|
{ |
||||
|
Debug.LogWarning("MotionVectorScale contains scale value greater than MaxRenderSize"); |
||||
|
} |
||||
|
|
||||
|
if (dispatchParams.MotionVectorScale.x == 0.0f || dispatchParams.MotionVectorScale.y == 0.0f) |
||||
|
{ |
||||
|
Debug.LogWarning("MotionVectorScale contains zero scale value"); |
||||
|
} |
||||
|
|
||||
|
if (dispatchParams.RenderSize.x > _contextDescription.MaxRenderSize.x || dispatchParams.RenderSize.y > _contextDescription.MaxRenderSize.y) |
||||
|
{ |
||||
|
Debug.LogWarning("RenderSize is greater than context MaxRenderSize"); |
||||
|
} |
||||
|
|
||||
|
if (dispatchParams.RenderSize.x == 0 || dispatchParams.RenderSize.y == 0) |
||||
|
{ |
||||
|
Debug.LogWarning("RenderSize contains zero dimension"); |
||||
|
} |
||||
|
|
||||
|
if (dispatchParams.FrameTimeDelta > 1.0f) |
||||
|
{ |
||||
|
Debug.LogWarning("FrameTimeDelta is greater than 1.0f - this value should be seconds (~0.0166 for 60fps)"); |
||||
|
} |
||||
|
|
||||
|
if (dispatchParams.PreExposure == 0.0f) |
||||
|
{ |
||||
|
Debug.LogError("PreExposure provided as 0.0f which is invalid"); |
||||
|
} |
||||
|
|
||||
|
bool infiniteDepth = (_contextDescription.Flags & Asr.InitializationFlags.EnableDepthInfinite) != 0; |
||||
|
bool inverseDepth = (_contextDescription.Flags & Asr.InitializationFlags.EnableDepthInverted) != 0; |
||||
|
|
||||
|
if (inverseDepth) |
||||
|
{ |
||||
|
if (dispatchParams.CameraNear < dispatchParams.CameraFar) |
||||
|
{ |
||||
|
Debug.LogWarning("EnableDepthInverted flag is present yet CameraNear is less than CameraFar"); |
||||
|
} |
||||
|
|
||||
|
if (infiniteDepth) |
||||
|
{ |
||||
|
if (dispatchParams.CameraNear < float.MaxValue) |
||||
|
{ |
||||
|
Debug.LogWarning("EnableDepthInfinite and EnableDepthInverted present, yet CameraNear != float.MaxValue"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (dispatchParams.CameraFar < 0.075f) |
||||
|
{ |
||||
|
Debug.LogWarning("EnableDepthInverted present, CameraFar value is very low which may result in depth separation artefacting"); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (dispatchParams.CameraNear > dispatchParams.CameraFar) |
||||
|
{ |
||||
|
Debug.LogWarning("CameraNear is greater than CameraFar in non-inverted-depth context"); |
||||
|
} |
||||
|
|
||||
|
if (infiniteDepth) |
||||
|
{ |
||||
|
if (dispatchParams.CameraFar < float.MaxValue) |
||||
|
{ |
||||
|
Debug.LogWarning("EnableDepthInfinite present, yet CameraFar != float.MaxValue"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (dispatchParams.CameraNear < 0.075f) |
||||
|
{ |
||||
|
Debug.LogWarning("CameraNear value is very low which may result in depth separation artefacting"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (dispatchParams.CameraFovAngleVertical <= 0.0f) |
||||
|
{ |
||||
|
Debug.LogError("CameraFovAngleVertical is 0.0f - this value should be > 0.0f"); |
||||
|
} |
||||
|
|
||||
|
if (dispatchParams.CameraFovAngleVertical > Mathf.PI) |
||||
|
{ |
||||
|
Debug.LogError("CameraFovAngleVertical is greater than 180 degrees/PI"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The ASR C++ codebase uses floats bitwise converted to ints to pass sharpness parameters to the RCAS shader.
|
||||
|
/// This is not possible in C# without enabling unsafe code compilation, so to avoid that we instead use a table of precomputed values.
|
||||
|
/// </summary>
|
||||
|
private static readonly Asr.RcasConstants[] RcasConfigs = new [] |
||||
|
{ |
||||
|
new Asr.RcasConstants(1048576000u, 872428544u), |
||||
|
new Asr.RcasConstants(1049178080u, 877212745u), |
||||
|
new Asr.RcasConstants(1049823372u, 882390168u), |
||||
|
new Asr.RcasConstants(1050514979u, 887895276u), |
||||
|
new Asr.RcasConstants(1051256227u, 893859143u), |
||||
|
new Asr.RcasConstants(1052050675u, 900216232u), |
||||
|
new Asr.RcasConstants(1052902144u, 907032080u), |
||||
|
new Asr.RcasConstants(1053814727u, 914306687u), |
||||
|
new Asr.RcasConstants(1054792807u, 922105590u), |
||||
|
new Asr.RcasConstants(1055841087u, 930494326u), |
||||
|
new Asr.RcasConstants(1056964608u, 939538432u), |
||||
|
new Asr.RcasConstants(1057566688u, 944322633u), |
||||
|
new Asr.RcasConstants(1058211980u, 949500056u), |
||||
|
new Asr.RcasConstants(1058903587u, 955005164u), |
||||
|
new Asr.RcasConstants(1059644835u, 960969031u), |
||||
|
new Asr.RcasConstants(1060439283u, 967326120u), |
||||
|
new Asr.RcasConstants(1061290752u, 974141968u), |
||||
|
new Asr.RcasConstants(1062203335u, 981416575u), |
||||
|
new Asr.RcasConstants(1063181415u, 989215478u), |
||||
|
new Asr.RcasConstants(1064229695u, 997604214u), |
||||
|
new Asr.RcasConstants(1065353216u, 1006648320), |
||||
|
}; |
||||
|
|
||||
|
private static ComputeBuffer CreateConstantBuffer<TConstants>() where TConstants: struct |
||||
|
{ |
||||
|
return new ComputeBuffer(1, Marshal.SizeOf<TConstants>(), ComputeBufferType.Constant); |
||||
|
} |
||||
|
|
||||
|
private static void DestroyConstantBuffer(ref ComputeBuffer bufferRef) |
||||
|
{ |
||||
|
if (bufferRef == null) |
||||
|
return; |
||||
|
|
||||
|
bufferRef.Release(); |
||||
|
bufferRef = null; |
||||
|
} |
||||
|
|
||||
|
private static void DestroyPass(ref AsrPass pass) |
||||
|
{ |
||||
|
if (pass == null) |
||||
|
return; |
||||
|
|
||||
|
pass.Dispose(); |
||||
|
pass = null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
fileFormatVersion: 2 |
||||
|
guid: c348b7c44539db74994c5846caec5871 |
||||
|
MonoImporter: |
||||
|
externalObjects: {} |
||||
|
serializedVersion: 2 |
||||
|
defaultReferences: [] |
||||
|
executionOrder: 0 |
||||
|
icon: {instanceID: 0} |
||||
|
userData: |
||||
|
assetBundleName: |
||||
|
assetBundleVariant: |
||||
@ -0,0 +1,339 @@ |
|||||
|
// Copyright (c) 2024 Nico de Poel
|
||||
|
//
|
||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
// in the Software without restriction, including without limitation the rights
|
||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||
|
// furnished to do so, subject to the following conditions:
|
||||
|
//
|
||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||
|
// copies or substantial portions of the Software.
|
||||
|
//
|
||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
|
// THE SOFTWARE.
|
||||
|
|
||||
|
using System; |
||||
|
using UnityEngine; |
||||
|
using UnityEngine.Profiling; |
||||
|
using UnityEngine.Rendering; |
||||
|
|
||||
|
namespace ArmASR |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Base class for all the compute passes that make up the ASR process.
|
||||
|
/// This loosely matches the FfxPipelineState struct from the original ASR codebase, wrapped in an object-oriented blanket.
|
||||
|
/// These classes are responsible for loading compute shaders, managing temporary resources, binding resources to shader kernels and dispatching said shaders.
|
||||
|
/// </summary>
|
||||
|
internal abstract class AsrPass: IDisposable |
||||
|
{ |
||||
|
internal const int ShadingChangeMipLevel = 4; // This matches the FFXM_FSR2_SHADING_CHANGE_MIP_LEVEL define
|
||||
|
|
||||
|
protected readonly Asr.ContextDescription ContextDescription; |
||||
|
protected readonly AsrResources Resources; |
||||
|
protected readonly ComputeBuffer Constants; |
||||
|
|
||||
|
protected ComputeShader ComputeShader; |
||||
|
protected int KernelIndex; |
||||
|
|
||||
|
protected CustomSampler Sampler; |
||||
|
|
||||
|
protected AsrPass(Asr.ContextDescription contextDescription, AsrResources resources, ComputeBuffer constants) |
||||
|
{ |
||||
|
ContextDescription = contextDescription; |
||||
|
Resources = resources; |
||||
|
Constants = constants; |
||||
|
} |
||||
|
|
||||
|
public virtual void Dispose() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public void ScheduleDispatch(CommandBuffer commandBuffer, Asr.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) |
||||
|
{ |
||||
|
commandBuffer.BeginSample(Sampler); |
||||
|
DoScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchX, dispatchY); |
||||
|
commandBuffer.EndSample(Sampler); |
||||
|
} |
||||
|
|
||||
|
protected abstract void DoScheduleDispatch(CommandBuffer commandBuffer, Asr.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY); |
||||
|
|
||||
|
protected void InitComputeShader(string passName, ComputeShader shader) |
||||
|
{ |
||||
|
InitComputeShader(passName, shader, ContextDescription.Flags); |
||||
|
} |
||||
|
|
||||
|
private void InitComputeShader(string passName, ComputeShader shader, Asr.InitializationFlags flags) |
||||
|
{ |
||||
|
if (shader == null) |
||||
|
{ |
||||
|
throw new MissingReferenceException($"Shader for ASR pass '{passName}' could not be loaded! Please ensure it is included in the project correctly."); |
||||
|
} |
||||
|
|
||||
|
ComputeShader = shader; |
||||
|
KernelIndex = ComputeShader.FindKernel("main"); |
||||
|
Sampler = CustomSampler.Create(passName); |
||||
|
|
||||
|
bool useLut = false; |
||||
|
#if UNITY_2022_1_OR_NEWER // This will also work in 2020.3.43+ and 2021.3.14+
|
||||
|
if (SystemInfo.computeSubGroupSize == 64) |
||||
|
{ |
||||
|
useLut = true; |
||||
|
} |
||||
|
#endif
|
||||
|
|
||||
|
// This matches the permutation rules from the CreatePipeline* functions
|
||||
|
if ((flags & Asr.InitializationFlags.EnableHighDynamicRange) != 0) ComputeShader.EnableKeyword("FFXM_FSR2_OPTION_HDR_COLOR_INPUT"); |
||||
|
if ((flags & Asr.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) ComputeShader.EnableKeyword("FFXM_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS"); |
||||
|
if ((flags & Asr.InitializationFlags.EnableMotionVectorsJitterCancellation) != 0) ComputeShader.EnableKeyword("FFXM_FSR2_OPTION_JITTERED_MOTION_VECTORS"); |
||||
|
if ((flags & Asr.InitializationFlags.EnableDepthInverted) != 0) ComputeShader.EnableKeyword("FFXM_FSR2_OPTION_INVERTED_DEPTH"); |
||||
|
if (useLut) ComputeShader.EnableKeyword("FFXM_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE"); |
||||
|
if ((flags & Asr.InitializationFlags.EnableFP16Usage) != 0) ComputeShader.EnableKeyword("FFXM_HALF"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal class AsrComputeLuminancePyramidPass : AsrPass |
||||
|
{ |
||||
|
private readonly ComputeBuffer _spdConstants; |
||||
|
|
||||
|
public AsrComputeLuminancePyramidPass(Asr.ContextDescription contextDescription, AsrResources resources, ComputeBuffer constants, ComputeBuffer spdConstants) |
||||
|
: base(contextDescription, resources, constants) |
||||
|
{ |
||||
|
_spdConstants = spdConstants; |
||||
|
|
||||
|
InitComputeShader("Compute Luminance Pyramid", contextDescription.Shaders.computeLuminancePyramidPass); |
||||
|
} |
||||
|
|
||||
|
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Asr.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) |
||||
|
{ |
||||
|
ref var color = ref dispatchParams.Color; |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement); |
||||
|
|
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.UavExposureMipLumaChange, Resources.SceneLuminance, ShadingChangeMipLevel); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.UavExposureMip5, Resources.SceneLuminance, 5); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.UavAutoExposure, Resources.AutoExposure); |
||||
|
|
||||
|
commandBuffer.SetComputeConstantBufferParam(ComputeShader, AsrShaderIDs.CbFsr2, Constants, 0, Constants.stride); |
||||
|
commandBuffer.SetComputeConstantBufferParam(ComputeShader, AsrShaderIDs.CbSpd, _spdConstants, 0, _spdConstants.stride); |
||||
|
|
||||
|
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal class AsrReconstructPreviousDepthPass : AsrPass |
||||
|
{ |
||||
|
public AsrReconstructPreviousDepthPass(Asr.ContextDescription contextDescription, AsrResources resources, ComputeBuffer constants) |
||||
|
: base(contextDescription, resources, constants) |
||||
|
{ |
||||
|
InitComputeShader("Reconstruct & Dilate", contextDescription.Shaders.reconstructPreviousDepthPass); |
||||
|
} |
||||
|
|
||||
|
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Asr.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) |
||||
|
{ |
||||
|
ref var color = ref dispatchParams.Color; |
||||
|
ref var depth = ref dispatchParams.Depth; |
||||
|
ref var motionVectors = ref dispatchParams.MotionVectors; |
||||
|
ref var exposure = ref dispatchParams.Exposure; |
||||
|
|
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInputDepth, depth.RenderTarget, depth.MipLevel, depth.SubElement); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement); |
||||
|
|
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.UavDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]); |
||||
|
|
||||
|
commandBuffer.SetComputeConstantBufferParam(ComputeShader, AsrShaderIDs.CbFsr2, Constants, 0, Constants.stride); |
||||
|
|
||||
|
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal class AsrDepthClipPass : AsrPass |
||||
|
{ |
||||
|
public AsrDepthClipPass(Asr.ContextDescription contextDescription, AsrResources resources, ComputeBuffer constants) |
||||
|
: base(contextDescription, resources, constants) |
||||
|
{ |
||||
|
InitComputeShader("Depth Clip", contextDescription.Shaders.depthClipPass); |
||||
|
} |
||||
|
|
||||
|
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Asr.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) |
||||
|
{ |
||||
|
ref var color = ref dispatchParams.Color; |
||||
|
ref var depth = ref dispatchParams.Depth; |
||||
|
ref var motionVectors = ref dispatchParams.MotionVectors; |
||||
|
ref var exposure = ref dispatchParams.Exposure; |
||||
|
ref var reactive = ref dispatchParams.Reactive; |
||||
|
ref var tac = ref dispatchParams.TransparencyAndComposition; |
||||
|
|
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInputDepth, depth.RenderTarget, depth.MipLevel, depth.SubElement); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvReactiveMask, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvTransparencyAndCompositionMask, tac.RenderTarget, tac.MipLevel, tac.SubElement); |
||||
|
|
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvReconstructedPrevNearestDepth, AsrShaderIDs.UavReconstructedPrevNearestDepth); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvDilatedDepth, AsrShaderIDs.UavDilatedDepth); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvPrevDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex ^ 1]); |
||||
|
|
||||
|
commandBuffer.SetComputeConstantBufferParam(ComputeShader, AsrShaderIDs.CbFsr2, Constants, 0, Constants.stride); |
||||
|
|
||||
|
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal class AsrLockPass : AsrPass |
||||
|
{ |
||||
|
public AsrLockPass(Asr.ContextDescription contextDescription, AsrResources resources, ComputeBuffer constants) |
||||
|
: base(contextDescription, resources, constants) |
||||
|
{ |
||||
|
InitComputeShader("Create Locks", contextDescription.Shaders.lockPass); |
||||
|
} |
||||
|
|
||||
|
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Asr.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) |
||||
|
{ |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvLockInputLuma, AsrShaderIDs.UavLockInputLuma); |
||||
|
commandBuffer.SetComputeConstantBufferParam(ComputeShader, AsrShaderIDs.CbFsr2, Constants, 0, Constants.stride); |
||||
|
|
||||
|
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal class AsrAccumulatePass : AsrPass |
||||
|
{ |
||||
|
private const string SharpeningKeyword = "FFXM_FSR2_OPTION_APPLY_SHARPENING"; |
||||
|
|
||||
|
#if UNITY_2021_2_OR_NEWER
|
||||
|
private readonly LocalKeyword _sharpeningKeyword; |
||||
|
#endif
|
||||
|
|
||||
|
public AsrAccumulatePass(Asr.ContextDescription contextDescription, AsrResources resources, ComputeBuffer constants) |
||||
|
: base(contextDescription, resources, constants) |
||||
|
{ |
||||
|
InitComputeShader("Reproject & Accumulate", contextDescription.Shaders.accumulatePass); |
||||
|
#if UNITY_2021_2_OR_NEWER
|
||||
|
_sharpeningKeyword = new LocalKeyword(ComputeShader, SharpeningKeyword); |
||||
|
#endif
|
||||
|
} |
||||
|
|
||||
|
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Asr.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) |
||||
|
{ |
||||
|
#if UNITY_2021_2_OR_NEWER
|
||||
|
if (dispatchParams.EnableSharpening) |
||||
|
commandBuffer.EnableKeyword(ComputeShader, _sharpeningKeyword); |
||||
|
else |
||||
|
commandBuffer.DisableKeyword(ComputeShader, _sharpeningKeyword); |
||||
|
#else
|
||||
|
if (dispatchParams.EnableSharpening) |
||||
|
commandBuffer.EnableShaderKeyword(SharpeningKeyword); |
||||
|
else |
||||
|
commandBuffer.DisableShaderKeyword(SharpeningKeyword); |
||||
|
#endif
|
||||
|
|
||||
|
if ((ContextDescription.Flags & Asr.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) |
||||
|
{ |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
ref var motionVectors = ref dispatchParams.MotionVectors; |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement); |
||||
|
} |
||||
|
|
||||
|
ref var exposure = ref dispatchParams.Exposure; |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement); |
||||
|
|
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvDilatedReactiveMasks, AsrShaderIDs.UavDilatedReactiveMasks); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[frameIndex ^ 1]); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvLockStatus, Resources.LockStatus[frameIndex ^ 1]); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvPreparedInputColor, AsrShaderIDs.UavPreparedInputColor); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvLanczosLut, Resources.LanczosLut); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvUpscaleMaximumBiasLut, Resources.MaximumBiasLut); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvSceneLuminanceMips, Resources.SceneLuminance); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvAutoExposure, Resources.AutoExposure); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvLumaHistory, Resources.LumaHistory[frameIndex ^ 1]); |
||||
|
|
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.UavInternalUpscaled, Resources.InternalUpscaled[frameIndex]); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.UavLockStatus, Resources.LockStatus[frameIndex]); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.UavLumaHistory, Resources.LumaHistory[frameIndex]); |
||||
|
|
||||
|
ref var output = ref dispatchParams.Output; |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.UavUpscaledOutput, output.RenderTarget, output.MipLevel, output.SubElement); |
||||
|
|
||||
|
commandBuffer.SetComputeConstantBufferParam(ComputeShader, AsrShaderIDs.CbFsr2, Constants, 0, Constants.stride); |
||||
|
|
||||
|
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal class AsrSharpenPass : AsrPass |
||||
|
{ |
||||
|
private readonly ComputeBuffer _rcasConstants; |
||||
|
|
||||
|
public AsrSharpenPass(Asr.ContextDescription contextDescription, AsrResources resources, ComputeBuffer constants, ComputeBuffer rcasConstants) |
||||
|
: base(contextDescription, resources, constants) |
||||
|
{ |
||||
|
_rcasConstants = rcasConstants; |
||||
|
|
||||
|
InitComputeShader("RCAS Sharpening", contextDescription.Shaders.sharpenPass); |
||||
|
} |
||||
|
|
||||
|
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Asr.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) |
||||
|
{ |
||||
|
ref var exposure = ref dispatchParams.Exposure; |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvRcasInput, Resources.InternalUpscaled[frameIndex]); |
||||
|
|
||||
|
ref var output = ref dispatchParams.Output; |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.UavUpscaledOutput, output.RenderTarget, output.MipLevel, output.SubElement); |
||||
|
|
||||
|
commandBuffer.SetComputeConstantBufferParam(ComputeShader, AsrShaderIDs.CbFsr2, Constants, 0, Constants.stride); |
||||
|
commandBuffer.SetComputeConstantBufferParam(ComputeShader, AsrShaderIDs.CbRcas, _rcasConstants, 0, _rcasConstants.stride); |
||||
|
|
||||
|
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal class AsrGenerateReactivePass : AsrPass |
||||
|
{ |
||||
|
private readonly ComputeBuffer _generateReactiveConstants; |
||||
|
|
||||
|
public AsrGenerateReactivePass(Asr.ContextDescription contextDescription, AsrResources resources, ComputeBuffer generateReactiveConstants) |
||||
|
: base(contextDescription, resources, null) |
||||
|
{ |
||||
|
_generateReactiveConstants = generateReactiveConstants; |
||||
|
|
||||
|
InitComputeShader("Auto-Generate Reactive Mask", contextDescription.Shaders.autoGenReactivePass); |
||||
|
} |
||||
|
|
||||
|
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Asr.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public void ScheduleDispatch(CommandBuffer commandBuffer, Asr.GenerateReactiveDescription dispatchParams, int dispatchX, int dispatchY) |
||||
|
{ |
||||
|
commandBuffer.BeginSample(Sampler); |
||||
|
|
||||
|
ref var opaqueOnly = ref dispatchParams.ColorOpaqueOnly; |
||||
|
ref var color = ref dispatchParams.ColorPreUpscale; |
||||
|
ref var reactive = ref dispatchParams.OutReactive; |
||||
|
|
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvOpaqueOnly, opaqueOnly.RenderTarget, opaqueOnly.MipLevel, opaqueOnly.SubElement); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement); |
||||
|
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, AsrShaderIDs.UavAutoReactive, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement); |
||||
|
|
||||
|
commandBuffer.SetComputeConstantBufferParam(ComputeShader, AsrShaderIDs.CbGenReactive, _generateReactiveConstants, 0, _generateReactiveConstants.stride); |
||||
|
|
||||
|
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1); |
||||
|
|
||||
|
commandBuffer.EndSample(Sampler); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
fileFormatVersion: 2 |
||||
|
guid: 7fb53d9f929886c4ab35be8d9010b9c3 |
||||
|
MonoImporter: |
||||
|
externalObjects: {} |
||||
|
serializedVersion: 2 |
||||
|
defaultReferences: [] |
||||
|
executionOrder: 0 |
||||
|
icon: {instanceID: 0} |
||||
|
userData: |
||||
|
assetBundleName: |
||||
|
assetBundleVariant: |
||||
@ -0,0 +1,227 @@ |
|||||
|
// Copyright (c) 2024 Nico de Poel
|
||||
|
//
|
||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
// in the Software without restriction, including without limitation the rights
|
||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||
|
// furnished to do so, subject to the following conditions:
|
||||
|
//
|
||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||
|
// copies or substantial portions of the Software.
|
||||
|
//
|
||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
|
// THE SOFTWARE.
|
||||
|
|
||||
|
using System; |
||||
|
using UnityEngine; |
||||
|
using UnityEngine.Experimental.Rendering; |
||||
|
using UnityEngine.Rendering; |
||||
|
|
||||
|
namespace ArmASR |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Helper class for bundling and managing persistent resources required by the ASR process.
|
||||
|
/// This includes lookup tables, default fallback resources and double-buffered resources that get swapped between frames.
|
||||
|
/// </summary>
|
||||
|
internal class AsrResources |
||||
|
{ |
||||
|
public Texture2D DefaultExposure; |
||||
|
public Texture2D DefaultReactive; |
||||
|
public Texture2D LanczosLut; |
||||
|
public Texture2D MaximumBiasLut; |
||||
|
public RenderTexture SpdAtomicCounter; |
||||
|
public RenderTexture AutoExposure; |
||||
|
public RenderTexture SceneLuminance; |
||||
|
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(Asr.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 = Asr.Lanczos2(x); |
||||
|
lanczos2Weights[currentLanczosWidthIndex] = y; |
||||
|
} |
||||
|
|
||||
|
float[] maximumBias = new float[MaximumBiasTextureWidth * MaximumBiasTextureHeight]; |
||||
|
for (int i = 0; i < maximumBias.Length; ++i) |
||||
|
{ |
||||
|
maximumBias[i] = MaximumBias[i] / 2.0f; |
||||
|
} |
||||
|
|
||||
|
// 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 = "ASR_LanczosLutData" }; |
||||
|
LanczosLut.SetPixelData(lanczos2Weights, 0); |
||||
|
LanczosLut.Apply(); |
||||
|
|
||||
|
// 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 = "ASR_MaximumUpsampleBias" }; |
||||
|
MaximumBiasLut.SetPixelData(maximumBias, 0); |
||||
|
MaximumBiasLut.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 = "ASR_DefaultExposure" }; |
||||
|
DefaultExposure.SetPixel(0, 0, Color.clear); |
||||
|
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 = "ASR_DefaultReactivityMask" }; |
||||
|
DefaultReactive.SetPixel(0, 0, Color.clear); |
||||
|
DefaultReactive.Apply(); |
||||
|
|
||||
|
// 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.
|
||||
|
SpdAtomicCounter = new RenderTexture(1, 1, 0, GraphicsFormat.R32_UInt) { name = "ASR_SpdAtomicCounter", enableRandomWrite = true }; |
||||
|
SpdAtomicCounter.Create(); |
||||
|
|
||||
|
// Resource FSR2_AutoExposure: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE
|
||||
|
AutoExposure = new RenderTexture(1, 1, 0, GraphicsFormat.R32G32_SFloat) { name = "ASR_AutoExposure", enableRandomWrite = true }; |
||||
|
AutoExposure.Create(); |
||||
|
|
||||
|
// Resource FSR2_ExposureMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
|
||||
|
// This is a rather special case: it's an aliasable resource, but because we require a mipmap chain and bind specific mip levels per shader, we can't easily use temporary RTs for this.
|
||||
|
int w = contextDescription.MaxRenderSize.x / 2, h = contextDescription.MaxRenderSize.y / 2; |
||||
|
int mipCount = 1 + Mathf.FloorToInt(Mathf.Log(Math.Max(w, h), 2.0f)); |
||||
|
SceneLuminance = new RenderTexture(w, h, 0, GraphicsFormat.R16_SFloat, mipCount) { name = "ASR_ExposureMips", enableRandomWrite = true, useMipMap = true, autoGenerateMips = false }; |
||||
|
SceneLuminance.Create(); |
||||
|
|
||||
|
// Resources FSR2_InternalDilatedVelocity1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_NONE
|
||||
|
CreateDoubleBufferedResource(DilatedMotionVectors, "ASR_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, "ASR_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, "ASR_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, "ASR_LumaHistory", contextDescription.DisplaySize, GraphicsFormat.R8G8B8A8_UNorm); |
||||
|
} |
||||
|
|
||||
|
// Set up shared aliasable resources, i.e. temporary render textures
|
||||
|
// These do not need to persist between frames, but they do need to be available between passes
|
||||
|
public static void CreateAliasableResources(CommandBuffer commandBuffer, Asr.ContextDescription contextDescription, Asr.DispatchDescription dispatchParams) |
||||
|
{ |
||||
|
Vector2Int displaySize = contextDescription.DisplaySize; |
||||
|
Vector2Int maxRenderSize = contextDescription.MaxRenderSize; |
||||
|
|
||||
|
// FSR2_ReconstructedPrevNearestDepth: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE
|
||||
|
commandBuffer.GetTemporaryRT(AsrShaderIDs.UavReconstructedPrevNearestDepth, maxRenderSize.x, maxRenderSize.y, 0, default, GraphicsFormat.R32_UInt, 1, true); |
||||
|
|
||||
|
// FSR2_DilatedDepth: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
|
||||
|
commandBuffer.GetTemporaryRT(AsrShaderIDs.UavDilatedDepth, maxRenderSize.x, maxRenderSize.y, 0, default, GraphicsFormat.R32_SFloat, 1, true); |
||||
|
|
||||
|
// FSR2_LockInputLuma: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
|
||||
|
commandBuffer.GetTemporaryRT(AsrShaderIDs.UavLockInputLuma, maxRenderSize.x, maxRenderSize.y, 0, default, GraphicsFormat.R16_SFloat, 1, true); |
||||
|
|
||||
|
// FSR2_DilatedReactiveMasks: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8G8_UNORM, FFX_RESOURCE_FLAGS_ALIASABLE
|
||||
|
commandBuffer.GetTemporaryRT(AsrShaderIDs.UavDilatedReactiveMasks, maxRenderSize.x, maxRenderSize.y, 0, default, GraphicsFormat.R8G8_UNorm, 1, true); |
||||
|
|
||||
|
// FSR2_PreparedInputColor: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
|
||||
|
commandBuffer.GetTemporaryRT(AsrShaderIDs.UavPreparedInputColor, maxRenderSize.x, maxRenderSize.y, 0, default, GraphicsFormat.R16G16B16A16_SFloat, 1, true); |
||||
|
|
||||
|
// FSR2_NewLocks: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_ALIASABLE
|
||||
|
commandBuffer.GetTemporaryRT(AsrShaderIDs.UavNewLocks, displaySize.x, displaySize.y, 0, default, GraphicsFormat.R8_UNorm, 1, true); |
||||
|
} |
||||
|
|
||||
|
public static void DestroyAliasableResources(CommandBuffer commandBuffer) |
||||
|
{ |
||||
|
// Release all of the aliasable resources used this frame
|
||||
|
commandBuffer.ReleaseTemporaryRT(AsrShaderIDs.UavReconstructedPrevNearestDepth); |
||||
|
commandBuffer.ReleaseTemporaryRT(AsrShaderIDs.UavDilatedDepth); |
||||
|
commandBuffer.ReleaseTemporaryRT(AsrShaderIDs.UavLockInputLuma); |
||||
|
commandBuffer.ReleaseTemporaryRT(AsrShaderIDs.UavDilatedReactiveMasks); |
||||
|
commandBuffer.ReleaseTemporaryRT(AsrShaderIDs.UavPreparedInputColor); |
||||
|
commandBuffer.ReleaseTemporaryRT(AsrShaderIDs.UavNewLocks); |
||||
|
} |
||||
|
|
||||
|
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, 0, format) { name = name + (i + 1), enableRandomWrite = true }; |
||||
|
resource[i].Create(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void Destroy() |
||||
|
{ |
||||
|
DestroyResource(LumaHistory); |
||||
|
DestroyResource(InternalUpscaled); |
||||
|
DestroyResource(LockStatus); |
||||
|
DestroyResource(DilatedMotionVectors); |
||||
|
DestroyResource(ref SceneLuminance); |
||||
|
DestroyResource(ref AutoExposure); |
||||
|
DestroyResource(ref DefaultReactive); |
||||
|
DestroyResource(ref DefaultExposure); |
||||
|
DestroyResource(ref MaximumBiasLut); |
||||
|
DestroyResource(ref LanczosLut); |
||||
|
} |
||||
|
|
||||
|
private static void DestroyResource(ref Texture2D resource) |
||||
|
{ |
||||
|
if (resource == null) |
||||
|
return; |
||||
|
|
||||
|
#if UNITY_EDITOR
|
||||
|
if (Application.isPlaying && !UnityEditor.EditorApplication.isPaused) |
||||
|
UnityEngine.Object.Destroy(resource); |
||||
|
else |
||||
|
UnityEngine.Object.DestroyImmediate(resource); |
||||
|
#else
|
||||
|
UnityEngine.Object.Destroy(resource); |
||||
|
#endif
|
||||
|
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]); |
||||
|
} |
||||
|
|
||||
|
private const int MaximumBiasTextureWidth = 16; |
||||
|
private const int MaximumBiasTextureHeight = 16; |
||||
|
private static readonly float[] MaximumBias = |
||||
|
{ |
||||
|
2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.876f, 1.809f, 1.772f, 1.753f, 1.748f, |
||||
|
2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.869f, 1.801f, 1.764f, 1.745f, 1.739f, |
||||
|
2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.976f, 1.841f, 1.774f, 1.737f, 1.716f, 1.71f, |
||||
|
2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.914f, 1.784f, 1.716f, 1.673f, 1.649f, 1.641f, |
||||
|
2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.793f, 1.676f, 1.604f, 1.562f, 1.54f, 1.533f, |
||||
|
2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.802f, 1.619f, 1.536f, 1.492f, 1.467f, 1.454f, 1.449f, |
||||
|
2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.812f, 1.575f, 1.496f, 1.456f, 1.432f, 1.416f, 1.408f, 1.405f, |
||||
|
2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.555f, 1.479f, 1.438f, 1.413f, 1.398f, 1.387f, 1.381f, 1.379f, |
||||
|
2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.812f, 1.555f, 1.474f, 1.43f, 1.404f, 1.387f, 1.376f, 1.368f, 1.363f, 1.362f, |
||||
|
2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.802f, 1.575f, 1.479f, 1.43f, 1.401f, 1.382f, 1.369f, 1.36f, 1.354f, 1.351f, 1.35f, |
||||
|
2.0f, 2.0f, 1.976f, 1.914f, 1.793f, 1.619f, 1.496f, 1.438f, 1.404f, 1.382f, 1.367f, 1.357f, 1.349f, 1.344f, 1.341f, 1.34f, |
||||
|
1.876f, 1.869f, 1.841f, 1.784f, 1.676f, 1.536f, 1.456f, 1.413f, 1.387f, 1.369f, 1.357f, 1.347f, 1.341f, 1.336f, 1.333f, 1.332f, |
||||
|
1.809f, 1.801f, 1.774f, 1.716f, 1.604f, 1.492f, 1.432f, 1.398f, 1.376f, 1.36f, 1.349f, 1.341f, 1.335f, 1.33f, 1.328f, 1.327f, |
||||
|
1.772f, 1.764f, 1.737f, 1.673f, 1.562f, 1.467f, 1.416f, 1.387f, 1.368f, 1.354f, 1.344f, 1.336f, 1.33f, 1.326f, 1.323f, 1.323f, |
||||
|
1.753f, 1.745f, 1.716f, 1.649f, 1.54f, 1.454f, 1.408f, 1.381f, 1.363f, 1.351f, 1.341f, 1.333f, 1.328f, 1.323f, 1.321f, 1.32f, |
||||
|
1.748f, 1.739f, 1.71f, 1.641f, 1.533f, 1.449f, 1.405f, 1.379f, 1.362f, 1.35f, 1.34f, 1.332f, 1.327f, 1.323f, 1.32f, 1.319f, |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
fileFormatVersion: 2 |
||||
|
guid: 538f6eefa95c8ee4d9f6a9bc4bb3188e |
||||
|
MonoImporter: |
||||
|
externalObjects: {} |
||||
|
serializedVersion: 2 |
||||
|
defaultReferences: [] |
||||
|
executionOrder: 0 |
||||
|
icon: {instanceID: 0} |
||||
|
userData: |
||||
|
assetBundleName: |
||||
|
assetBundleVariant: |
||||
@ -0,0 +1,75 @@ |
|||||
|
// Copyright (c) 2024 Nico de Poel
|
||||
|
//
|
||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
// in the Software without restriction, including without limitation the rights
|
||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||
|
// furnished to do so, subject to the following conditions:
|
||||
|
//
|
||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||
|
// copies or substantial portions of the Software.
|
||||
|
//
|
||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
|
// THE SOFTWARE.
|
||||
|
|
||||
|
using UnityEngine; |
||||
|
|
||||
|
namespace ArmASR |
||||
|
{ |
||||
|
public static class AsrShaderIDs |
||||
|
{ |
||||
|
// Shader resource views, i.e. read-only bindings
|
||||
|
public static readonly int SrvInputColor = Shader.PropertyToID("r_input_color_jittered"); |
||||
|
public static readonly int SrvOpaqueOnly = Shader.PropertyToID("r_input_opaque_only"); |
||||
|
public static readonly int SrvInputMotionVectors = Shader.PropertyToID("r_input_motion_vectors"); |
||||
|
public static readonly int SrvInputDepth = Shader.PropertyToID("r_input_depth"); |
||||
|
public static readonly int SrvInputExposure = Shader.PropertyToID("r_input_exposure"); |
||||
|
public static readonly int SrvAutoExposure = Shader.PropertyToID("r_auto_exposure"); |
||||
|
public static readonly int SrvReactiveMask = Shader.PropertyToID("r_reactive_mask"); |
||||
|
public static readonly int SrvTransparencyAndCompositionMask = Shader.PropertyToID("r_transparency_and_composition_mask"); |
||||
|
public static readonly int SrvReconstructedPrevNearestDepth = Shader.PropertyToID("r_reconstructed_previous_nearest_depth"); |
||||
|
public static readonly int SrvDilatedMotionVectors = Shader.PropertyToID("r_dilated_motion_vectors"); |
||||
|
public static readonly int SrvPrevDilatedMotionVectors = Shader.PropertyToID("r_previous_dilated_motion_vectors"); |
||||
|
public static readonly int SrvDilatedDepth = Shader.PropertyToID("r_dilatedDepth"); |
||||
|
public static readonly int SrvInternalUpscaled = Shader.PropertyToID("r_internal_upscaled_color"); |
||||
|
public static readonly int SrvLockStatus = Shader.PropertyToID("r_lock_status"); |
||||
|
public static readonly int SrvLockInputLuma = Shader.PropertyToID("r_lock_input_luma"); |
||||
|
public static readonly int SrvPreparedInputColor = Shader.PropertyToID("r_prepared_input_color"); |
||||
|
public static readonly int SrvLumaHistory = Shader.PropertyToID("r_luma_history"); |
||||
|
public static readonly int SrvRcasInput = Shader.PropertyToID("r_rcas_input"); |
||||
|
public static readonly int SrvLanczosLut = Shader.PropertyToID("r_lanczos_lut"); |
||||
|
public static readonly int SrvSceneLuminanceMips = Shader.PropertyToID("r_imgMips"); |
||||
|
public static readonly int SrvUpscaleMaximumBiasLut = Shader.PropertyToID("r_upsample_maximum_bias_lut"); |
||||
|
public static readonly int SrvDilatedReactiveMasks = Shader.PropertyToID("r_dilated_reactive_masks"); |
||||
|
|
||||
|
// Unordered access views, i.e. random read/write bindings
|
||||
|
public static readonly int UavReconstructedPrevNearestDepth = Shader.PropertyToID("rw_reconstructed_previous_nearest_depth"); |
||||
|
public static readonly int UavDilatedMotionVectors = Shader.PropertyToID("rw_dilated_motion_vectors"); |
||||
|
public static readonly int UavDilatedDepth = Shader.PropertyToID("rw_dilatedDepth"); |
||||
|
public static readonly int UavInternalUpscaled = Shader.PropertyToID("rw_internal_upscaled_color"); |
||||
|
public static readonly int UavLockStatus = Shader.PropertyToID("rw_lock_status"); |
||||
|
public static readonly int UavLockInputLuma = Shader.PropertyToID("rw_lock_input_luma"); |
||||
|
public static readonly int UavNewLocks = Shader.PropertyToID("rw_new_locks"); |
||||
|
public static readonly int UavPreparedInputColor = Shader.PropertyToID("rw_prepared_input_color"); |
||||
|
public static readonly int UavLumaHistory = Shader.PropertyToID("rw_luma_history"); |
||||
|
public static readonly int UavUpscaledOutput = Shader.PropertyToID("rw_upscaled_output"); |
||||
|
public static readonly int UavExposureMipLumaChange = Shader.PropertyToID("rw_img_mip_shading_change"); |
||||
|
public static readonly int UavExposureMip5 = Shader.PropertyToID("rw_img_mip_5"); |
||||
|
public static readonly int UavDilatedReactiveMasks = Shader.PropertyToID("rw_dilated_reactive_masks"); |
||||
|
public static readonly int UavAutoExposure = Shader.PropertyToID("rw_auto_exposure"); |
||||
|
public static readonly int UavSpdAtomicCount = Shader.PropertyToID("rw_spd_global_atomic"); |
||||
|
public static readonly int UavAutoReactive = Shader.PropertyToID("rw_output_autoreactive"); |
||||
|
|
||||
|
// Constant buffer bindings
|
||||
|
public static readonly int CbFsr2 = Shader.PropertyToID("cbFSR2"); |
||||
|
public static readonly int CbSpd = Shader.PropertyToID("cbSPD"); |
||||
|
public static readonly int CbRcas = Shader.PropertyToID("cbRCAS"); |
||||
|
public static readonly int CbGenReactive = Shader.PropertyToID("cbGenerateReactive"); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
fileFormatVersion: 2 |
||||
|
guid: e0173241f8bd75e419590b43a3739e0e |
||||
|
MonoImporter: |
||||
|
externalObjects: {} |
||||
|
serializedVersion: 2 |
||||
|
defaultReferences: [] |
||||
|
executionOrder: 0 |
||||
|
icon: {instanceID: 0} |
||||
|
userData: |
||||
|
assetBundleName: |
||||
|
assetBundleVariant: |
||||
@ -0,0 +1,55 @@ |
|||||
|
// Copyright (c) 2024 Nico de Poel
|
||||
|
//
|
||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
// in the Software without restriction, including without limitation the rights
|
||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||
|
// furnished to do so, subject to the following conditions:
|
||||
|
//
|
||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||
|
// copies or substantial portions of the Software.
|
||||
|
//
|
||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
|
// THE SOFTWARE.
|
||||
|
|
||||
|
using UnityEngine.Rendering; |
||||
|
|
||||
|
namespace ArmASR |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// An immutable structure wrapping all the necessary information to bind a specific buffer or attachment of a render target to a compute shader.
|
||||
|
/// </summary>
|
||||
|
public readonly struct ResourceView |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// This value is the equivalent of not setting any value at all; all struct fields will have their default values.
|
||||
|
/// It does not refer to a valid texture, therefore any variable set to this value should be checked for IsValid and reassigned before being bound to a shader.
|
||||
|
/// </summary>
|
||||
|
public static readonly ResourceView Unassigned = new ResourceView(default); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This value contains a valid texture reference that can be bound to a shader, however it is just an empty placeholder texture.
|
||||
|
/// Binding this to a shader can be seen as setting the texture variable inside the shader to null.
|
||||
|
/// </summary>
|
||||
|
public static readonly ResourceView None = new ResourceView(BuiltinRenderTextureType.None); |
||||
|
|
||||
|
public ResourceView(in RenderTargetIdentifier renderTarget, RenderTextureSubElement subElement = RenderTextureSubElement.Default, int mipLevel = 0) |
||||
|
{ |
||||
|
RenderTarget = renderTarget; |
||||
|
SubElement = subElement; |
||||
|
MipLevel = mipLevel; |
||||
|
} |
||||
|
|
||||
|
public bool IsValid => !RenderTarget.Equals(default); |
||||
|
|
||||
|
public readonly RenderTargetIdentifier RenderTarget; |
||||
|
public readonly RenderTextureSubElement SubElement; |
||||
|
public readonly int MipLevel; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
fileFormatVersion: 2 |
||||
|
guid: 6e2e3cd4f5c3d4146b6fe3f93685751b |
||||
|
MonoImporter: |
||||
|
externalObjects: {} |
||||
|
serializedVersion: 2 |
||||
|
defaultReferences: [] |
||||
|
executionOrder: 0 |
||||
|
icon: {instanceID: 0} |
||||
|
userData: |
||||
|
assetBundleName: |
||||
|
assetBundleVariant: |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue