2025-04-17 15:58:05 +08:00

313 lines
10 KiB
C#

using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using UnityEngine;
using FidelityFX;
[assembly: InternalsVisibleTo("com.alteregogames.aeg-fsr.Runtime.BIRP")]
[assembly: InternalsVisibleTo("com.alteregogames.aeg-fsr.Runtime.URP")]
[assembly: InternalsVisibleTo("com.alteregogames.aeg-fsr.Runtime.HDRP")]
namespace AEG.FSR
{
/// <summary>
/// Base script for FSR
/// </summary>
[RequireComponent(typeof(Camera))]
public abstract class FSR3_BASE : MonoBehaviour
{
//Public Variables
public FSR_Quality FSRQuality = FSR_Quality.Balanced;
[Range(0, 1)]
public float antiGhosting = 0.0f;
public static float FSRScaleFactor;
public bool sharpening = true;
public float sharpness = 0.5f;
public bool enableF16;
public bool enableAutoExposure = true;
public bool generateReactiveMask = true;
public bool generateTCMask = false;
public float autoReactiveScale = 0.9f;
public float autoReactiveThreshold = 0.05f;
public float autoReactiveBinaryValue = 0.5f;
public float autoTcThreshold = 0.05f;
public float autoTcScale = 1f;
public float autoTcReactiveScale = 5f;
public float autoTcReactiveMax = 0.9f;
public Fsr3.GenerateReactiveFlags reactiveFlags = Fsr3.GenerateReactiveFlags.ApplyTonemap | Fsr3.GenerateReactiveFlags.ApplyThreshold | Fsr3.GenerateReactiveFlags.UseComponentsMax;
public float mipmapBiasOverride = 1.0f;
public bool autoTextureUpdate = true;
public float mipMapUpdateFrequency = 2f;
//Protected Variables
protected bool m_fsrInitialized = false;
protected Camera m_mainCamera;
protected float m_scaleFactor = 1.5f;
protected int m_renderWidth, m_renderHeight;
protected int m_displayWidth, m_displayHeight;
protected float m_nearClipPlane, m_farClipPlane, m_fieldOfView;
protected FSR_Quality m_previousFsrQuality;
protected bool m_previousHDR;
protected bool m_previousReactiveMask;
protected bool m_previousTCMask;
protected float m_previousScaleFactor;
protected RenderingPath m_previousRenderingPath;
//Mipmap variables
protected Texture[] m_allTextures;
protected ulong m_previousLength;
protected float m_mipMapBias;
protected float m_prevMipMapBias;
protected float m_mipMapTimer = float.MaxValue;
public bool m_resetCamera = false;
#region Public API
/// <summary>
/// Set FSR Quality settings.
/// Quality = 1.5, Balanced = 1.7, Performance = 2, Ultra Performance = 3
/// </summary>
public void OnSetQuality(FSR_Quality value) {
m_previousFsrQuality = value;
FSRQuality = value;
if(value == FSR_Quality.Off) {
Initialize();
DisableFSR();
m_scaleFactor = 1;
} else {
switch(value) {
case FSR_Quality.TemporalAntiAliasingOnly:
m_scaleFactor = 1.0f;
break;
case FSR_Quality.Quality:
m_scaleFactor = 1.5f;
break;
case FSR_Quality.Balanced:
m_scaleFactor = 1.7f;
break;
case FSR_Quality.Performance:
m_scaleFactor = 2.0f;
break;
case FSR_Quality.UltraPerformance:
m_scaleFactor = 3.0f;
break;
}
Initialize();
}
FSRScaleFactor = m_scaleFactor;
}
public void OnSetAdaptiveQuality(float _value) {
m_scaleFactor = _value;
}
/// <summary>
/// Checks wether FSR is compatible using the current build settings
/// </summary>
/// <returns></returns>
public bool OnIsSupported() {
bool fsr2Compatible = SystemInfo.supportsComputeShaders;
enableF16 = SystemInfo.IsFormatSupported(UnityEngine.Experimental.Rendering.GraphicsFormat.R16_SFloat, UnityEngine.Experimental.Rendering.FormatUsage.Render);
return fsr2Compatible;
}
/// <summary>
/// Resets the camera for the next frame, clearing all the buffers saved from previous frames in order to prevent artifacts.
/// Should be called in or before PreRender oh the frame where the camera makes a jumpcut.
/// Is automatically disabled the frame after.
/// </summary>
public void OnResetCamera() {
m_resetCamera = true;
}
/// <summary>
/// Updates a single texture to the set MipMap Bias.
/// Should be called when an object is instantiated, or when the ScaleFactor is changed.
/// </summary>
public void OnMipmapSingleTexture(Texture texture) {
texture.mipMapBias = m_mipMapBias;
}
/// <summary>
/// Updates all textures currently loaded to the set MipMap Bias.
/// Should be called when a lot of new textures are loaded, or when the ScaleFactor is changed.
/// </summary>
public void OnMipMapAllTextures() {
m_allTextures = Resources.FindObjectsOfTypeAll(typeof(Texture)) as Texture[];
for(int i = 0; i < m_allTextures.Length; i++) {
m_allTextures[i].mipMapBias = m_mipMapBias;
}
}
/// <summary>
/// Resets all currently loaded textures to the default mipmap bias.
/// </summary>
public void OnResetAllMipMaps() {
m_prevMipMapBias = -1;
m_allTextures = Resources.FindObjectsOfTypeAll(typeof(Texture)) as Texture[];
for(int i = 0; i < m_allTextures.Length; i++) {
m_allTextures[i].mipMapBias = 0;
}
m_allTextures = null;
}
#endregion
protected virtual void Initialize() {
bool fsr2Compatible = OnIsSupported();
//Reset mipmap timer so mipmap are instantly updated if automatic mip map is turned on
m_mipMapTimer = float.MaxValue;
if(m_fsrInitialized || !Application.isPlaying) {
return;
}
if(fsr2Compatible) {
InitializeFSR();
m_fsrInitialized = true;
} else {
Debug.LogWarning($"FSR 2 is not supported");
enabled = false;
}
}
/// <summary>
/// Initializes everything in order to run FSR
/// </summary>
protected virtual void InitializeFSR() {
m_mainCamera = GetComponent<Camera>();
}
protected virtual void OnEnable() {
#if AMD_FIDELITY_FSR3_DEBUG
RegisterDebugCallback(OnDebugCallback);
#endif
OnSetQuality(FSRQuality);
}
protected virtual void Update() {
if(m_previousFsrQuality != FSRQuality) {
OnSetQuality(FSRQuality);
}
if(!m_fsrInitialized) {
return;
}
#if UNITY_BIRP
if(autoTextureUpdate) {
UpdateMipMaps();
}
#endif
}
protected virtual void OnDisable() {
DisableFSR();
}
protected virtual void OnDestroy() {
DisableFSR();
}
/// <summary>
/// Disables FSR and cleans up
/// </summary>
protected virtual void DisableFSR() {
m_fsrInitialized = false;
}
#region Automatic Mip Map
#if UNITY_BIRP
/// <summary>
/// Automatically updates the mipmap of all loaded textures
/// </summary>
protected void UpdateMipMaps() {
m_mipMapTimer += Time.deltaTime;
if(m_mipMapTimer > mipMapUpdateFrequency) {
m_mipMapTimer = 0;
m_mipMapBias = (Mathf.Log((float)(m_renderWidth) / (float)(m_displayWidth), 2f) - 1) * mipmapBiasOverride;
if(m_previousLength != Texture.currentTextureMemory || m_prevMipMapBias != m_mipMapBias) {
m_prevMipMapBias = m_mipMapBias;
m_previousLength = Texture.currentTextureMemory;
OnMipMapAllTextures();
}
}
}
#endif
#endregion
#region Debug
#if AMD_FIDELITY_FSR3_DEBUG
/// <summary>
/// Register a callback to send debugging information
/// </summary>
/// <param name="cb"></param>
[DllImport(m_DLL, CallingConvention = CallingConvention.Cdecl)]
static extern void RegisterDebugCallback(debugCallback cb);
/// <summary>
/// Delegate for a debug callback
/// </summary>
delegate void debugCallback(IntPtr request, int messageType, int color, int size);
enum Color { red, green, blue, black, white, yellow, orange };
enum MessageType { Error, Warning, Info };
/// <summary>
/// Callback for debug messages send from the plugin
/// </summary>
/// <param name="request">Debug message</param>
/// <param name="messageType">Message type</param>
/// <param name="color">Color to use in the console</param>
/// <param name="size">Size of the string</param>
static void OnDebugCallback(IntPtr request, int messageType, int color, int size)
{
//Ptr to string
string debug_string = Marshal.PtrToStringAnsi(request, size);
//Add Specified Color
debug_string =
String.Format("{0}{1}{2}",
$"<color={(Color)color}>",
debug_string,
"</color>"
);
switch ((MessageType)messageType)
{
case MessageType.Error:
Debug.LogError(debug_string);
break;
case MessageType.Warning:
Debug.LogWarning(debug_string);
break;
default:
Debug.Log(debug_string);
break;
}
}
#endif
#endregion
}
}