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
Nico de Poel 11 months ago
parent
commit
d3f60e2650
  1. 8
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime.meta
  2. 292
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/Asr.cs
  3. 11
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/Asr.cs.meta
  4. 152
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrAssets.cs
  5. 11
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrAssets.cs.meta
  6. 81
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrCallbacks.cs
  7. 11
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrCallbacks.cs.meta
  8. 570
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrContext.cs
  9. 11
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrContext.cs.meta
  10. 339
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrPass.cs
  11. 11
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrPass.cs.meta
  12. 227
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrResources.cs
  13. 11
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrResources.cs.meta
  14. 75
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrShaderIDs.cs
  15. 11
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrShaderIDs.cs.meta
  16. 55
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/ResourceView.cs
  17. 11
      Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/ResourceView.cs.meta

8
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6bbfbdd9fd482bd4ea5e998953ae9972
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

292
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/Asr.cs

@ -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;
}
}
}

11
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/Asr.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c7350363c6d8a2b4096a9ed97dc4ed95
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

152
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrAssets.cs

@ -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);
}
}
}

11
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrAssets.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7a41695239eb36740847744b34c5af43
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

81
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrCallbacks.cs

@ -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);
}
}
}

11
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrCallbacks.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 78f16fcb80e6325429dfa567a4ed5d4a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

570
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrContext.cs

@ -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;
}
}
}

11
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrContext.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c348b7c44539db74994c5846caec5871
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

339
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrPass.cs

@ -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);
}
}
}

11
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrPass.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7fb53d9f929886c4ab35be8d9010b9c3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

227
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrResources.cs

@ -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,
};
}
}

11
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrResources.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 538f6eefa95c8ee4d9f6a9bc4bb3188e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

75
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrShaderIDs.cs

@ -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");
}
}

11
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/AsrShaderIDs.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e0173241f8bd75e419590b43a3739e0e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

55
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/ResourceView.cs

@ -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;
}
}

11
Packages/com.unity.postprocessing@3.2.2/PostProcessing/Runtime/Effects/Upscaling/ASR/Runtime/ResourceView.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6e2e3cd4f5c3d4146b6fe3f93685751b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
Loading…
Cancel
Save