Decompiled source of RepoRTGI v1.0.0

RepoRTGI.dll

Decompiled 10 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.XR;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RepoRTGI")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Screen-space ray-traced global illumination for R.E.P.O.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RepoRTGI")]
[assembly: AssemblyTitle("RepoRTGI")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace RepoRTGI
{
	internal static class BuildInfo
	{
		internal const string Version = "1.0.0";
	}
	internal sealed class GpuClassification
	{
		internal string Name { get; }

		internal string Reason { get; }

		internal bool IsAutomaticTier { get; }

		internal int VramMb { get; }

		internal GpuClassification(string name, bool isAutomaticTier, string reason, int vramMb)
		{
			Name = name;
			IsAutomaticTier = isAutomaticTier;
			Reason = reason;
			VramMb = vramMb;
		}
	}
	internal static class GpuClassifier
	{
		private static readonly Regex NvidiaModel = new Regex("RTX\\s*(\\d{4})", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);

		private static readonly Regex AmdModel = new Regex("RX\\s*(\\d{4,5})\\s*(XTX|XT)?", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);

		internal static GpuClassification Detect()
		{
			string text = SystemInfo.graphicsDeviceName ?? "Unknown GPU";
			int graphicsMemorySize = SystemInfo.graphicsMemorySize;
			string text2 = Regex.Replace(text.ToUpperInvariant(), "\\s+", " ");
			if (text2.Contains("MICROSOFT BASIC") || text2.Contains("REMOTE DISPLAY") || text2.Contains("VMWARE") || text2.Contains("VIRTUAL"))
			{
				return new GpuClassification(text, isAutomaticTier: false, "software or virtual graphics adapter", graphicsMemorySize);
			}
			Match match = NvidiaModel.Match(text2);
			if (match.Success && int.TryParse(match.Groups[1].Value, out var result))
			{
				if (text2.Contains("LAPTOP") || text2.Contains("MOBILE"))
				{
					return new GpuClassification(text, isAutomaticTier: false, "mobile GPU variants use manual activation because their power limits vary widely", graphicsMemorySize);
				}
				int num = result / 1000;
				int num2 = result % 1000;
				bool flag = num >= 6 || (num == 5 && num2 >= 70) || (num == 4 && (num2 >= 80 || text2.Contains("4070 TI"))) || (num == 3 && num2 >= 90);
				return new GpuClassification(text, flag, flag ? "NVIDIA GPU meets the RTX 5070-class automatic threshold" : "NVIDIA GPU is below the RTX 5070-class automatic threshold", graphicsMemorySize);
			}
			Match match2 = AmdModel.Match(text2);
			if (match2.Success && int.TryParse(match2.Groups[1].Value, out var result2))
			{
				string text3 = match2.Groups[2].Value.ToUpperInvariant();
				bool flag2 = result2 >= 10000 || result2 >= 9070 || (result2 == 7900 && text3 == "XTX");
				return new GpuClassification(text, flag2, flag2 ? "AMD GPU meets the RX 9070 / RTX 5070-class automatic threshold" : "AMD GPU is below the RTX 5070-class automatic threshold", graphicsMemorySize);
			}
			return new GpuClassification(text, isAutomaticTier: false, "GPU model is not in the conservative automatic-enable allowlist", graphicsMemorySize);
		}
	}
	internal static class NativeBridge
	{
		private const string NativeLibraryName = "RepoRTGI.Native";

		private static IntPtr _module;

		private static IntPtr _renderEvent;

		private static ManualLogSource? _log;

		internal static bool IsLoaded
		{
			get
			{
				if (_module != IntPtr.Zero)
				{
					return _renderEvent != IntPtr.Zero;
				}
				return false;
			}
		}

		internal static IntPtr RenderEvent => _renderEvent;

		internal static bool Load(string pluginDirectory, ManualLogSource log)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			_log = log;
			if ((int)Application.platform != 2)
			{
				log.LogWarning((object)"RepoRTGI native renderer currently supports the Windows player only.");
				return false;
			}
			string text = Path.Combine(pluginDirectory, "RepoRTGI.Native.dll");
			if (!File.Exists(text))
			{
				log.LogError((object)("Native renderer is missing: " + text));
				return false;
			}
			_module = LoadLibrary(text);
			if (_module == IntPtr.Zero)
			{
				log.LogError((object)$"Could not load RepoRTGI.Native.dll (Win32 error {Marshal.GetLastWin32Error()}).");
				return false;
			}
			try
			{
				_renderEvent = RepoRtgiGetRenderEventFunc();
			}
			catch (Exception ex)
			{
				log.LogError((object)("Native renderer entry point failed: " + ex.Message));
				return false;
			}
			if (_renderEvent == IntPtr.Zero)
			{
				log.LogError((object)"Native renderer returned an invalid render callback.");
				return false;
			}
			return true;
		}

		internal static bool Submit(int slot, ref NativeFrameRequest request)
		{
			if (!IsLoaded)
			{
				return false;
			}
			int num = RepoRtgiSubmitFrame(slot, ref request);
			if (num == 0)
			{
				return true;
			}
			string lastError = GetLastError();
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogWarning((object)$"Native RTGI frame was rejected ({num}): {lastError}");
			}
			return false;
		}

		internal static string GetLastError()
		{
			if (_module == IntPtr.Zero)
			{
				return "native module is not loaded";
			}
			StringBuilder stringBuilder = new StringBuilder(1024);
			RepoRtgiGetLastError(stringBuilder, stringBuilder.Capacity);
			return stringBuilder.ToString();
		}

		internal static int GetStatus()
		{
			if (!(_module == IntPtr.Zero))
			{
				return RepoRtgiGetStatus();
			}
			return -1;
		}

		internal static void Shutdown()
		{
			_renderEvent = IntPtr.Zero;
		}

		[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
		private static extern IntPtr LoadLibrary(string fileName);

		[DllImport("RepoRTGI.Native", CallingConvention = CallingConvention.Cdecl, EntryPoint = "RepoRtgi_GetRenderEventFunc")]
		private static extern IntPtr RepoRtgiGetRenderEventFunc();

		[DllImport("RepoRTGI.Native", CallingConvention = CallingConvention.Cdecl, EntryPoint = "RepoRtgi_SubmitFrame")]
		private static extern int RepoRtgiSubmitFrame(int slot, ref NativeFrameRequest request);

		[DllImport("RepoRTGI.Native", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "RepoRtgi_GetLastError")]
		private static extern void RepoRtgiGetLastError(StringBuilder buffer, int capacity);

		[DllImport("RepoRTGI.Native", CallingConvention = CallingConvention.Cdecl, EntryPoint = "RepoRtgi_GetStatus")]
		private static extern int RepoRtgiGetStatus();
	}
	internal struct NativeFrameRequest
	{
		internal IntPtr Source;

		internal IntPtr Destination;

		internal IntPtr DepthNormals;

		internal IntPtr HistoryRead;

		internal IntPtr HistoryWrite;

		internal int Width;

		internal int Height;

		internal int GiWidth;

		internal int GiHeight;

		internal int RayCount;

		internal int StepCount;

		internal int FrameIndex;

		internal int ResetHistory;

		internal float RayDistance;

		internal float Thickness;

		internal float Intensity;

		internal float Saturation;

		internal float TemporalWeight;

		internal float DenoiseRadius;

		internal float FarClip;

		internal float Projection11;

		internal float Projection22;
	}
	[BepInPlugin("ModsForGames.RepoRTGI", "R.E.P.O. RTGI", "1.0.0")]
	public sealed class RepoRtgiPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "ModsForGames.RepoRTGI";

		public const string PluginName = "R.E.P.O. RTGI";

		private static RepoRtgiPlugin? _instance;

		private static RtgiConfig _config = null;

		private static GpuClassification _gpu = null;

		private static bool _sessionDisabled;

		private static bool _depthWarningReported;

		private static Camera? _renderCamera;

		private static FieldInfo? _gameDirectorInstanceField;

		private static FieldInfo? _gameDirectorMainCameraField;

		private static readonly List<XRDisplaySubsystem> XrDisplays = new List<XRDisplaySubsystem>();

		private int _nextNativeStatusCheck;

		private int _nextCameraCheck;

		private bool _nativeErrorReported;

		private bool _nativeReadyReported;

		internal static ManualLogSource Log => ((BaseUnityPlugin)_instance).Logger;

		internal static RtgiSettings Settings => _config.Resolve();

		internal static bool ShouldRender
		{
			get
			{
				if ((Object)(object)_instance == (Object)null || _sessionDisabled)
				{
					return false;
				}
				if (IsVrRunning())
				{
					return false;
				}
				string value = _config.Activation.Value;
				if (!(value == "Enabled"))
				{
					if (value == "Disabled")
					{
						return false;
					}
					return _gpu.IsAutomaticTier;
				}
				return true;
			}
		}

		internal static bool IsRenderCamera(Camera camera)
		{
			return (Object)(object)_renderCamera == (Object)(object)camera;
		}

		private static bool IsVrRunning()
		{
			SubsystemManager.GetInstances<XRDisplaySubsystem>(XrDisplays);
			foreach (XRDisplaySubsystem xrDisplay in XrDisplays)
			{
				if (((IntegratedSubsystem)xrDisplay).running)
				{
					return true;
				}
			}
			return false;
		}

		private void Awake()
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Invalid comparison between Unknown and I4
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			_instance = this;
			_config = new RtgiConfig(((BaseUnityPlugin)this).Config);
			_gpu = GpuClassifier.Detect();
			_config.Changed += OnConfigChanged;
			bool flag = NativeBridge.Load(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? Paths.PluginPath, ((BaseUnityPlugin)this).Logger);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"R.E.P.O. RTGI v1.0.0 loaded.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"GPU: {_gpu.Name} ({_gpu.VramMb} MB). {_gpu.Reason}.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Graphics API: {SystemInfo.graphicsDeviceType}.");
			if ((int)SystemInfo.graphicsDeviceType != 2)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"RTGI requires Direct3D 11. Start R.E.P.O. with -force-d3d11 to use the effect.");
			}
			else if (flag)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)(ShouldRender ? "RTGI is active. Change Mode in REPOConfig to disable it." : "RTGI is bypassed. Automatic mode did not enable it for this GPU; manual Enabled remains available."));
			}
			Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnAnyCameraPreCull));
		}

		private void Update()
		{
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			if (Time.frameCount >= _nextCameraCheck)
			{
				_nextCameraCheck = Time.frameCount + 60;
				EnsureRenderCamera();
			}
			if (NativeBridge.IsLoaded && !_nativeErrorReported && Time.frameCount >= _nextNativeStatusCheck)
			{
				_nextNativeStatusCheck = Time.frameCount + 120;
				int status = NativeBridge.GetStatus();
				if (status > 0 && !_nativeReadyReported)
				{
					_nativeReadyReported = true;
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Native RTGI renderer initialized successfully.");
				}
				else if (status < 0)
				{
					_nativeErrorReported = true;
					((BaseUnityPlugin)this).Logger.LogError((object)("Native RTGI renderer stopped: " + NativeBridge.GetLastError()));
				}
			}
			if (Enum.TryParse<KeyCode>(_config.ToggleKey.Value, ignoreCase: true, out KeyCode result) && Input.GetKeyDown(result))
			{
				_sessionDisabled = !_sessionDisabled;
				RefreshAttachedEffects(resetHistory: true);
				((BaseUnityPlugin)this).Logger.LogInfo((object)(_sessionDisabled ? "RTGI disabled for this session." : "RTGI session override cleared."));
			}
		}

		private void OnAnyCameraPreCull(Camera camera)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			if (ShouldRender && NativeBridge.IsLoaded && (int)SystemInfo.graphicsDeviceType == 2)
			{
				Camera val = ResolveRenderCamera();
				if ((Object)(object)val == (Object)null && LooksLikeWorldCamera(camera))
				{
					_renderCamera = camera;
					val = camera;
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Selected fallback render camera '" + ((Object)camera).name + "'."));
				}
				if (!((Object)(object)camera != (Object)(object)val) && !((Object)(object)((Component)camera).GetComponent<RtgiCameraEffect>() != (Object)null))
				{
					((Component)camera).gameObject.AddComponent<RtgiCameraEffect>();
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Attached RTGI to render camera '" + ((Object)camera).name + "'."));
				}
			}
		}

		private void EnsureRenderCamera()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			if (!ShouldRender || !NativeBridge.IsLoaded || (int)SystemInfo.graphicsDeviceType != 2)
			{
				RefreshAttachedEffects();
				return;
			}
			Camera val = ResolveRenderCamera();
			if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).GetComponent<RtgiCameraEffect>() == (Object)null)
			{
				((Component)val).gameObject.AddComponent<RtgiCameraEffect>();
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Attached RTGI to render camera '" + ((Object)val).name + "'."));
			}
			RefreshAttachedEffects();
		}

		private static bool LooksLikeWorldCamera(Camera camera)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			if (!((Behaviour)camera).enabled || !((Component)camera).gameObject.activeInHierarchy || (int)camera.cameraType != 1 || camera.cullingMask == 0)
			{
				return false;
			}
			string text = ((Object)camera).name.ToLowerInvariant();
			if (!text.Contains("overlay") && !text.Contains("ui") && !text.Contains("map") && !text.Contains("preview"))
			{
				return !text.Contains("icon");
			}
			return false;
		}

		private void OnConfigChanged()
		{
			_sessionDisabled = false;
			Camera val = ResolveRenderCamera();
			if (ShouldRender && (Object)(object)val != (Object)null && (Object)(object)((Component)val).GetComponent<RtgiCameraEffect>() == (Object)null)
			{
				((Component)val).gameObject.AddComponent<RtgiCameraEffect>();
			}
			RefreshAttachedEffects(resetHistory: true);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("RTGI settings updated. Effective state: " + (ShouldRender ? "enabled" : "disabled") + "."));
		}

		private static void RefreshAttachedEffects(bool resetHistory = false)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			Camera val = ResolveRenderCamera();
			bool flag = ShouldRender && NativeBridge.IsLoaded && (int)SystemInfo.graphicsDeviceType == 2;
			RtgiCameraEffect[] array = Object.FindObjectsOfType<RtgiCameraEffect>();
			foreach (RtgiCameraEffect rtgiCameraEffect in array)
			{
				bool flag2 = flag && (Object)(object)rtgiCameraEffect.TargetCamera == (Object)(object)val;
				if (((Behaviour)rtgiCameraEffect).enabled != flag2)
				{
					((Behaviour)rtgiCameraEffect).enabled = flag2;
				}
				if (flag2 && resetHistory)
				{
					rtgiCameraEffect.ResetHistory();
				}
			}
		}

		private static Camera? ResolveRenderCamera()
		{
			Camera val = null;
			try
			{
				if (_gameDirectorInstanceField == null || _gameDirectorMainCameraField == null)
				{
					Type? type = Type.GetType("GameDirector, Assembly-CSharp");
					_gameDirectorInstanceField = type?.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					_gameDirectorMainCameraField = type?.GetField("MainCamera", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				object obj = _gameDirectorInstanceField?.GetValue(null);
				if (obj != null)
				{
					object? obj2 = _gameDirectorMainCameraField?.GetValue(obj);
					val = (Camera)((obj2 is Camera) ? obj2 : null);
				}
			}
			catch (Exception ex)
			{
				if ((Object)(object)_instance != (Object)null)
				{
					((BaseUnityPlugin)_instance).Logger.LogDebug((object)("GameDirector camera lookup is not ready: " + ex.Message));
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				val = Camera.main;
			}
			if ((Object)(object)val != (Object)(object)_renderCamera)
			{
				_renderCamera = val;
				if ((Object)(object)val != (Object)null && (Object)(object)_instance != (Object)null)
				{
					((BaseUnityPlugin)_instance).Logger.LogInfo((object)("Selected render camera '" + ((Object)val).name + "'."));
				}
			}
			return _renderCamera;
		}

		internal static void ReportMissingDepthNormals()
		{
			if (!_depthWarningReported && !((Object)(object)_instance == (Object)null))
			{
				_depthWarningReported = true;
				((BaseUnityPlugin)_instance).Logger.LogWarning((object)"The main camera did not expose a depth-normal texture. RTGI will retry on later frames.");
			}
		}

		private void OnDestroy()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnAnyCameraPreCull));
			_config.Changed -= OnConfigChanged;
			NativeBridge.Shutdown();
			_instance = null;
		}
	}
	[DisallowMultipleComponent]
	[RequireComponent(typeof(Camera))]
	internal sealed class RtgiCameraEffect : MonoBehaviour
	{
		private Camera _camera;

		private RenderTexture? _historyA;

		private RenderTexture? _historyB;

		private RenderTexture? _composite;

		private bool _historyFlip;

		private bool _resetHistory = true;

		private int _frameIndex;

		internal Camera TargetCamera => _camera;

		private void Awake()
		{
			_camera = ((Component)this).GetComponent<Camera>();
		}

		private void OnEnable()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			Camera camera = _camera;
			camera.depthTextureMode = (DepthTextureMode)(camera.depthTextureMode | 2);
			_resetHistory = true;
		}

		private void OnPreCull()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			Camera camera = _camera;
			camera.depthTextureMode = (DepthTextureMode)(camera.depthTextureMode | 2);
		}

		internal void ResetHistory()
		{
			_resetHistory = true;
		}

		private void OnRenderImage(RenderTexture source, RenderTexture destination)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			if (!RepoRtgiPlugin.ShouldRender || !NativeBridge.IsLoaded || (int)SystemInfo.graphicsDeviceType != 2 || !RepoRtgiPlugin.IsRenderCamera(_camera))
			{
				Graphics.Blit((Texture)(object)source, destination);
				return;
			}
			Texture globalTexture = Shader.GetGlobalTexture("_CameraDepthNormalsTexture");
			RenderTexture val = (RenderTexture)(object)((globalTexture is RenderTexture) ? globalTexture : null);
			if ((Object)(object)val == (Object)null)
			{
				RepoRtgiPlugin.ReportMissingDepthNormals();
				Graphics.Blit((Texture)(object)source, destination);
				return;
			}
			RtgiSettings settings = RepoRtgiPlugin.Settings;
			EnsureTargets(source, settings.ResolutionScale);
			if ((Object)(object)_historyA == (Object)null || (Object)(object)_historyB == (Object)null || (Object)(object)_composite == (Object)null)
			{
				Graphics.Blit((Texture)(object)source, destination);
				return;
			}
			Graphics.Blit((Texture)(object)source, _composite);
			RenderTexture val2 = (_historyFlip ? _historyB : _historyA);
			RenderTexture val3 = (_historyFlip ? _historyA : _historyB);
			Matrix4x4 projectionMatrix = _camera.projectionMatrix;
			NativeFrameRequest request = new NativeFrameRequest
			{
				Source = ((Texture)source).GetNativeTexturePtr(),
				Destination = ((Texture)_composite).GetNativeTexturePtr(),
				DepthNormals = ((Texture)val).GetNativeTexturePtr(),
				HistoryRead = ((Texture)val2).GetNativeTexturePtr(),
				HistoryWrite = ((Texture)val3).GetNativeTexturePtr(),
				Width = ((Texture)source).width,
				Height = ((Texture)source).height,
				GiWidth = ((Texture)val3).width,
				GiHeight = ((Texture)val3).height,
				RayCount = settings.RayCount,
				StepCount = settings.StepCount,
				FrameIndex = _frameIndex,
				ResetHistory = (_resetHistory ? 1 : 0),
				RayDistance = settings.RayDistance,
				Thickness = settings.Thickness,
				Intensity = settings.Intensity,
				Saturation = settings.Saturation,
				TemporalWeight = settings.TemporalWeight,
				DenoiseRadius = settings.DenoiseRadius,
				FarClip = _camera.farClipPlane,
				Projection11 = projectionMatrix.m00,
				Projection22 = projectionMatrix.m11
			};
			int num = _frameIndex & 0xF;
			if (request.Source != IntPtr.Zero && request.Destination != IntPtr.Zero && request.DepthNormals != IntPtr.Zero && request.HistoryRead != IntPtr.Zero && request.HistoryWrite != IntPtr.Zero && NativeBridge.Submit(num, ref request))
			{
				GL.IssuePluginEvent(NativeBridge.RenderEvent, num);
				_historyFlip = !_historyFlip;
				_resetHistory = false;
				_frameIndex++;
			}
			Graphics.Blit((Texture)(object)_composite, destination);
		}

		private void EnsureTargets(RenderTexture source, float scale)
		{
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Expected O, but got Unknown
			int num = Mathf.Max(16, Mathf.RoundToInt((float)((Texture)source).width * scale));
			int num2 = Mathf.Max(16, Mathf.RoundToInt((float)((Texture)source).height * scale));
			if (!((Object)(object)_historyA != (Object)null) || !((Object)(object)_historyB != (Object)null) || !((Object)(object)_composite != (Object)null) || ((Texture)_historyA).width != num || ((Texture)_historyA).height != num2 || ((Texture)_composite).width != ((Texture)source).width || ((Texture)_composite).height != ((Texture)source).height)
			{
				ReleaseTargets();
				_historyA = CreateHistory(num, num2, "RepoRTGI History A");
				_historyB = CreateHistory(num, num2, "RepoRTGI History B");
				RenderTextureDescriptor descriptor = source.descriptor;
				((RenderTextureDescriptor)(ref descriptor)).depthBufferBits = 0;
				((RenderTextureDescriptor)(ref descriptor)).msaaSamples = 1;
				((RenderTextureDescriptor)(ref descriptor)).useMipMap = false;
				((RenderTextureDescriptor)(ref descriptor)).autoGenerateMips = false;
				((RenderTextureDescriptor)(ref descriptor)).enableRandomWrite = false;
				_composite = new RenderTexture(descriptor)
				{
					name = "RepoRTGI Composite",
					filterMode = (FilterMode)1,
					wrapMode = (TextureWrapMode)1,
					hideFlags = (HideFlags)61
				};
				_composite.Create();
				_historyFlip = false;
				_resetHistory = true;
				_frameIndex = 0;
			}
		}

		private static RenderTexture CreateHistory(int width, int height, string name)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			RenderTexture val = new RenderTexture(width, height, 0, (RenderTextureFormat)2, (RenderTextureReadWrite)1)
			{
				name = name,
				filterMode = (FilterMode)1,
				wrapMode = (TextureWrapMode)1,
				useMipMap = false,
				autoGenerateMips = false,
				hideFlags = (HideFlags)61
			};
			val.Create();
			return val;
		}

		private void OnDisable()
		{
			ReleaseTargets();
		}

		private void OnDestroy()
		{
			ReleaseTargets();
		}

		private void ReleaseTargets()
		{
			Release(ref _historyA);
			Release(ref _historyB);
			Release(ref _composite);
		}

		private static void Release(ref RenderTexture? texture)
		{
			if (!((Object)(object)texture == (Object)null))
			{
				texture.Release();
				Object.Destroy((Object)(object)texture);
				texture = null;
			}
		}
	}
	internal sealed class RtgiConfig
	{
		internal readonly ConfigEntry<string> Activation;

		internal readonly ConfigEntry<string> QualityPreset;

		internal readonly ConfigEntry<float> Intensity;

		internal readonly ConfigEntry<float> Saturation;

		internal readonly ConfigEntry<float> ResolutionScale;

		internal readonly ConfigEntry<int> RayCount;

		internal readonly ConfigEntry<int> StepCount;

		internal readonly ConfigEntry<float> RayDistance;

		internal readonly ConfigEntry<float> Thickness;

		internal readonly ConfigEntry<float> TemporalWeight;

		internal readonly ConfigEntry<int> DenoiseRadius;

		internal readonly ConfigEntry<string> ToggleKey;

		internal event Action? Changed;

		internal RtgiConfig(ConfigFile config)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Expected O, but got Unknown
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Expected O, but got Unknown
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Expected O, but got Unknown
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Expected O, but got Unknown
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Expected O, but got Unknown
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Expected O, but got Unknown
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Expected O, but got Unknown
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Expected O, but got Unknown
			Activation = config.Bind<string>("01. Activation", "Mode", "Automatic", new ConfigDescription("Automatic enables RTGI only on an RTX 5070-class or faster GPU. Enabled is a manual override. Disabled fully bypasses the renderer.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Automatic", "Enabled", "Disabled" }), Array.Empty<object>()));
			QualityPreset = config.Bind<string>("02. Quality", "Preset", "High", new ConfigDescription("Low, Medium, High and Ultra use tuned settings. Choose Custom to use every value in 03. Advanced.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[5] { "Low", "Medium", "High", "Ultra", "Custom" }), Array.Empty<object>()));
			Intensity = config.Bind<float>("02. Quality", "Indirect Light Intensity", 1f, new ConfigDescription("Strength of bounced indirect light.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			Saturation = config.Bind<float>("02. Quality", "Bounce Saturation", 1f, new ConfigDescription("Color saturation of bounced light. 0 is monochrome; 1 preserves the source color.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			ResolutionScale = config.Bind<float>("03. Advanced", "GI Resolution Scale", 0.75f, new ConfigDescription("Internal RTGI resolution. Used only by the Custom preset.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 1f), Array.Empty<object>()));
			RayCount = config.Bind<int>("03. Advanced", "Rays Per Pixel", 3, new ConfigDescription("Diffuse rays evaluated per pixel. Used only by the Custom preset.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), Array.Empty<object>()));
			StepCount = config.Bind<int>("03. Advanced", "Steps Per Ray", 28, new ConfigDescription("Maximum ray-march steps. Used only by the Custom preset.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(8, 64), Array.Empty<object>()));
			RayDistance = config.Bind<float>("03. Advanced", "Ray Distance", 25f, new ConfigDescription("Maximum view-space ray length. Used only by the Custom preset.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 60f), Array.Empty<object>()));
			Thickness = config.Bind<float>("03. Advanced", "Depth Thickness", 0.5f, new ConfigDescription("Screen-space hit thickness. Raise it when thin geometry loses bounced light. Used only by the Custom preset.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f), Array.Empty<object>()));
			TemporalWeight = config.Bind<float>("03. Advanced", "Temporal Stability", 0.85f, new ConfigDescription("History weight. Higher values reduce noise but may increase ghosting. Used only by the Custom preset.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.97f), Array.Empty<object>()));
			DenoiseRadius = config.Bind<int>("03. Advanced", "Denoise Radius", 2, new ConfigDescription("Edge-aware spatial filter radius. 0 disables spatial denoising. Used only by the Custom preset.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 3), Array.Empty<object>()));
			ToggleKey = config.Bind<string>("01. Activation", "Session Toggle Key", "F8", new ConfigDescription("Temporarily toggles the effect without changing saved settings.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[6] { "F5", "F6", "F7", "F8", "F9", "F10" }), Array.Empty<object>()));
			Subscribe<string>(Activation);
			Subscribe<string>(QualityPreset);
			Subscribe<float>(Intensity);
			Subscribe<float>(Saturation);
			Subscribe<float>(ResolutionScale);
			Subscribe<int>(RayCount);
			Subscribe<int>(StepCount);
			Subscribe<float>(RayDistance);
			Subscribe<float>(Thickness);
			Subscribe<float>(TemporalWeight);
			Subscribe<int>(DenoiseRadius);
			Subscribe<string>(ToggleKey);
		}

		internal RtgiSettings Resolve()
		{
			RtgiSettings result = QualityPreset.Value switch
			{
				"Low" => new RtgiSettings(0.5f, 1, 12, 12f, 0.8f, 0.72f, 1), 
				"Medium" => new RtgiSettings(0.66f, 2, 20, 18f, 0.65f, 0.8f, 1), 
				"Ultra" => new RtgiSettings(1f, 4, 40, 35f, 0.4f, 0.9f, 3), 
				"Custom" => new RtgiSettings(ResolutionScale.Value, RayCount.Value, StepCount.Value, RayDistance.Value, Thickness.Value, TemporalWeight.Value, DenoiseRadius.Value), 
				_ => new RtgiSettings(0.75f, 3, 28, 25f, 0.5f, 0.85f, 2), 
			};
			result.Intensity = Intensity.Value;
			result.Saturation = Saturation.Value;
			return result;
		}

		private void Subscribe<T>(ConfigEntry<T> entry)
		{
			entry.SettingChanged += delegate
			{
				this.Changed?.Invoke();
			};
		}
	}
	internal struct RtgiSettings
	{
		internal float ResolutionScale;

		internal int RayCount;

		internal int StepCount;

		internal float RayDistance;

		internal float Thickness;

		internal float TemporalWeight;

		internal int DenoiseRadius;

		internal float Intensity;

		internal float Saturation;

		internal RtgiSettings(float resolutionScale, int rayCount, int stepCount, float rayDistance, float thickness, float temporalWeight, int denoiseRadius)
		{
			ResolutionScale = resolutionScale;
			RayCount = rayCount;
			StepCount = stepCount;
			RayDistance = rayDistance;
			Thickness = thickness;
			TemporalWeight = temporalWeight;
			DenoiseRadius = denoiseRadius;
			Intensity = 1f;
			Saturation = 1f;
		}
	}
}