Decompiled source of DesktopBuddy v1.0.19

Renderer/BepInEx/plugins/DesktopBuddySharedTextureBridge/DesktopBuddySharedTextureBridge.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Concurrent;
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.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Logging;
using DesktopBuddy.Shared;
using HarmonyLib;
using InterprocessLib;
using Microsoft.CodeAnalysis;
using Renderite.Shared;
using Renderite.Unity;
using UMP;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("DesktopBuddySharedTextureBridge")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+ada0dbd4ce3dfe5ebcac1a80d6218629e829ef53")]
[assembly: AssemblyProduct("DesktopBuddySharedTextureBridge")]
[assembly: AssemblyTitle("DesktopBuddySharedTextureBridge")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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 DesktopBuddy.Shared
{
	internal static class SharedTextureBridgeProtocol
	{
		private const string BaseOwnerId = "DesktopBuddy.SharedTexture.v2";

		private const string BaseQueueName = "DesktopBuddy.SharedTexture.v2";

		private static readonly string QueueScope = GetQueueScope();

		public static readonly string OwnerId = GetScopedName("DesktopBuddy.SharedTexture.v2");

		public static readonly string QueueName = GetScopedName("DesktopBuddy.SharedTexture.v2");

		public const string StartMessageId = "Start";

		public const string StopMessageId = "Stop";

		public const string RunningMessageId = "Running";

		public const string StoppedMessageId = "Stopped";

		public const string RendererDeviceMessageId = "RendererDevice";

		public const int MaxTextureSlots = 4096;

		public const int MagicIndexBase = 10000;

		private static string GetScopedName(string baseName)
		{
			if (!string.IsNullOrEmpty(QueueScope))
			{
				return baseName + "." + QueueScope;
			}
			return baseName;
		}

		private static string GetQueueScope()
		{
			string value = GetArgumentValue("-shmprefix") ?? GetArgumentValue("--shmprefix");
			if (string.IsNullOrWhiteSpace(value))
			{
				return string.Empty;
			}
			return "shm" + ComputeStableHash(value).ToString("X16");
		}

		private static string GetArgumentValue(string name)
		{
			string[] commandLineArgs;
			try
			{
				commandLineArgs = Environment.GetCommandLineArgs();
			}
			catch
			{
				return null;
			}
			for (int i = 0; i < commandLineArgs.Length; i++)
			{
				string text = commandLineArgs[i];
				if (text == null)
				{
					continue;
				}
				if (string.Equals(text, name, StringComparison.OrdinalIgnoreCase))
				{
					if (i + 1 < commandLineArgs.Length)
					{
						return commandLineArgs[i + 1];
					}
					return null;
				}
				string text2 = name + "=";
				if (text.StartsWith(text2, StringComparison.OrdinalIgnoreCase))
				{
					return text.Substring(text2.Length);
				}
			}
			return null;
		}

		private static ulong ComputeStableHash(string value)
		{
			ulong num = 14695981039346656037uL;
			for (int i = 0; i < value.Length; i++)
			{
				num ^= value[i];
				num *= 1099511628211L;
			}
			return num;
		}
	}
	internal sealed class SimpleMemoryPackerPool : IMemoryPackerEntityPool
	{
		public static readonly SimpleMemoryPackerPool Instance = new SimpleMemoryPackerPool();

		private SimpleMemoryPackerPool()
		{
		}

		T IMemoryPackerEntityPool.Borrow<T>()
		{
			return new T();
		}

		void IMemoryPackerEntityPool.Return<T>(T value)
		{
		}
	}
	internal sealed class SharedTextureStartMessage : IMemoryPackable
	{
		public int SlotId;

		public int Generation;

		public long SharedTextureHandle;

		public string SharedTextureName;

		public int SharedTextureWidth;

		public int SharedTextureHeight;

		public void Pack(ref MemoryPacker packer)
		{
			((MemoryPacker)(ref packer)).Write<int>(SlotId);
			((MemoryPacker)(ref packer)).Write<int>(Generation);
			((MemoryPacker)(ref packer)).Write<long>(SharedTextureHandle);
			((MemoryPacker)(ref packer)).Write(SharedTextureName);
			((MemoryPacker)(ref packer)).Write<int>(SharedTextureWidth);
			((MemoryPacker)(ref packer)).Write<int>(SharedTextureHeight);
		}

		public void Unpack(ref MemoryUnpacker unpacker)
		{
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref SlotId);
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref Generation);
			((MemoryUnpacker)(ref unpacker)).Read<long>(ref SharedTextureHandle);
			((MemoryUnpacker)(ref unpacker)).Read(ref SharedTextureName);
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref SharedTextureWidth);
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref SharedTextureHeight);
		}
	}
	internal sealed class SharedTextureStopMessage : IMemoryPackable
	{
		public int SlotId;

		public int Generation;

		public void Pack(ref MemoryPacker packer)
		{
			((MemoryPacker)(ref packer)).Write<int>(SlotId);
			((MemoryPacker)(ref packer)).Write<int>(Generation);
		}

		public void Unpack(ref MemoryUnpacker unpacker)
		{
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref SlotId);
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref Generation);
		}
	}
	internal sealed class SharedTextureRunningMessage : IMemoryPackable
	{
		public int SlotId;

		public int Generation;

		public int Width;

		public int Height;

		public void Pack(ref MemoryPacker packer)
		{
			((MemoryPacker)(ref packer)).Write<int>(SlotId);
			((MemoryPacker)(ref packer)).Write<int>(Generation);
			((MemoryPacker)(ref packer)).Write<int>(Width);
			((MemoryPacker)(ref packer)).Write<int>(Height);
		}

		public void Unpack(ref MemoryUnpacker unpacker)
		{
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref SlotId);
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref Generation);
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref Width);
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref Height);
		}
	}
	internal sealed class SharedTextureStoppedMessage : IMemoryPackable
	{
		public int SlotId;

		public int Generation;

		public void Pack(ref MemoryPacker packer)
		{
			((MemoryPacker)(ref packer)).Write<int>(SlotId);
			((MemoryPacker)(ref packer)).Write<int>(Generation);
		}

		public void Unpack(ref MemoryUnpacker unpacker)
		{
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref SlotId);
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref Generation);
		}
	}
	internal sealed class SharedTextureRendererDeviceMessage : IMemoryPackable
	{
		public long AdapterLuid;

		public int VendorId;

		public string Description;

		public void Pack(ref MemoryPacker packer)
		{
			((MemoryPacker)(ref packer)).Write<long>(AdapterLuid);
			((MemoryPacker)(ref packer)).Write<int>(VendorId);
			((MemoryPacker)(ref packer)).Write(Description);
		}

		public void Unpack(ref MemoryUnpacker unpacker)
		{
			((MemoryUnpacker)(ref unpacker)).Read<long>(ref AdapterLuid);
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref VendorId);
			((MemoryUnpacker)(ref unpacker)).Read(ref Description);
		}
	}
}
namespace DesktopBuddySharedTextureBridge
{
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	internal static class LibVlcCachePatch
	{
		private struct CacheSettings
		{
			public int NetworkCachingMs;

			public int LiveCachingMs;

			public int FileCachingMs;

			public static CacheSettings Default
			{
				get
				{
					CacheSettings result = default(CacheSettings);
					result.NetworkCachingMs = 300;
					result.LiveCachingMs = 300;
					result.FileCachingMs = 300;
					return result;
				}
			}
		}

		private static DateTime _lastLoadUtc;

		private static CacheSettings _settings = CacheSettings.Default;

		private static bool _loggedConfigPath;

		private static void Prefix(PlayerOptionsStandalone options)
		{
			try
			{
				if (options != null)
				{
					CacheSettings cacheSettings = LoadSettings();
					options.NetworkCaching = cacheSettings.NetworkCachingMs;
					options.LiveCaching = cacheSettings.LiveCachingMs;
					options.FileCaching = cacheSettings.FileCachingMs;
					SharedTextureBridgePlugin.LogInfo($"[LibVLC] Cache options: network={options.NetworkCaching}ms live={options.LiveCaching}ms file={options.FileCaching}ms");
				}
			}
			catch (Exception ex)
			{
				SharedTextureBridgePlugin.LogError("[LibVLC] Prefix failed", ex);
			}
		}

		private static CacheSettings LoadSettings()
		{
			if ((DateTime.UtcNow - _lastLoadUtc).TotalSeconds < 2.0)
			{
				return _settings;
			}
			_lastLoadUtc = DateTime.UtcNow;
			string text = FindConfigPath();
			if (text == null || !File.Exists(text))
			{
				if (!_loggedConfigPath)
				{
					_loggedConfigPath = true;
					SharedTextureBridgePlugin.LogWarning("[LibVLC] DesktopBuddy BepInEx config not found; using low-latency cache defaults");
				}
				_settings = CacheSettings.Default;
				return _settings;
			}
			if (!_loggedConfigPath)
			{
				_loggedConfigPath = true;
				SharedTextureBridgePlugin.LogInfo("[LibVLC] Reading DesktopBuddy cache config from " + text);
			}
			try
			{
				string json = File.ReadAllText(text);
				CacheSettings settings = default(CacheSettings);
				settings.NetworkCachingMs = ReadCacheMs(json, "libVlcNetworkCachingMs", CacheSettings.Default.NetworkCachingMs);
				settings.LiveCachingMs = ReadCacheMs(json, "libVlcLiveCachingMs", CacheSettings.Default.LiveCachingMs);
				settings.FileCachingMs = ReadCacheMs(json, "libVlcFileCachingMs", CacheSettings.Default.FileCachingMs);
				_settings = settings;
			}
			catch (Exception ex)
			{
				SharedTextureBridgePlugin.LogError("[LibVLC] Failed to read DesktopBuddy cache config", ex);
				_settings = CacheSettings.Default;
			}
			return _settings;
		}

		private static string FindConfigPath()
		{
			string gameRootPath = Paths.GameRootPath;
			string text = Directory.GetParent(gameRootPath)?.FullName;
			string currentDirectory = Directory.GetCurrentDirectory();
			string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
			string directoryName = Path.GetDirectoryName(typeof(SharedTextureBridgePlugin).Assembly.Location);
			string[] array = new string[6]
			{
				Path.Combine(directoryName ?? "", "..", "..", "..", "..", "BepInEx", "config", "com.devl0rd.DesktopBuddy.cfg"),
				Path.Combine(gameRootPath ?? "", "BepInEx", "config", "com.devl0rd.DesktopBuddy.cfg"),
				Path.Combine(text ?? "", "BepInEx", "config", "com.devl0rd.DesktopBuddy.cfg"),
				Path.Combine(currentDirectory ?? "", "BepInEx", "config", "com.devl0rd.DesktopBuddy.cfg"),
				Path.Combine(baseDirectory ?? "", "..", "..", "..", "BepInEx", "config", "com.devl0rd.DesktopBuddy.cfg"),
				Path.Combine(baseDirectory ?? "", "..", "..", "..", "..", "BepInEx", "config", "com.devl0rd.DesktopBuddy.cfg")
			};
			foreach (string path in array)
			{
				try
				{
					string fullPath = Path.GetFullPath(path);
					if (File.Exists(fullPath))
					{
						return fullPath;
					}
				}
				catch
				{
				}
			}
			return null;
		}

		private static int ReadInt(string configText, string key, int fallback)
		{
			string text = Regex.Escape(key);
			Match match = Regex.Match(configText, "\"" + text + "\"\\s*:\\s*(-?\\d+)");
			if (!match.Success)
			{
				match = Regex.Match(configText, "(?m)^\\s*" + text + "\\s*=\\s*(-?\\d+)\\s*$");
			}
			if (!match.Success || !int.TryParse(match.Groups[1].Value, out var result))
			{
				return fallback;
			}
			if (result < 0)
			{
				return 0;
			}
			if (result > 5000)
			{
				return 5000;
			}
			return result;
		}

		private static int ReadCacheMs(string json, string key, int fallback)
		{
			return ReadInt(json, key, fallback);
		}
	}
	internal sealed class SharedTextureBridge : IDisposable
	{
		private readonly ManualLogSource _log;

		private readonly ConcurrentQueue<Action> _mainThreadActions = new ConcurrentQueue<Action>();

		private Messenger _messenger;

		private float _connectRetryTimer;

		private float _connectLogTimer;

		private const float ConnectRetryInterval = 1f;

		private const float ConnectLogInterval = 5f;

		private readonly Dictionary<int, SharedTextureSlot> _activeSlots = new Dictionary<int, SharedTextureSlot>();

		private readonly Dictionary<int, int> _activeGenerations = new Dictionary<int, int>();

		private static readonly ConcurrentDictionary<int, SharedTextureSlot> _bridgeIndexToSlot = new ConcurrentDictionary<int, SharedTextureSlot>();

		private readonly List<(int slot, int generation, SharedTextureSlot textureSlot)> _pendingBinds = new List<(int, int, SharedTextureSlot)>();

		private bool _rendererDevicePublished;

		internal int ActiveSlotCount => _activeSlots.Count;

		internal int PendingBindCount => _pendingBinds.Count;

		internal int TotalTextureRequestCount
		{
			get
			{
				int num = 0;
				foreach (SharedTextureSlot value in _activeSlots.Values)
				{
					num += value.RequestCount;
				}
				return num;
			}
		}

		internal SharedTextureBridge(ManualLogSource log)
		{
			_log = log;
			SharedTextureBridgePlugin.LogInfo("[SharedTextureBridge] Constructed");
		}

		internal static SharedTextureSlot GetSlotForBridgeIndex(int bridgeIndex)
		{
			_bridgeIndexToSlot.TryGetValue(bridgeIndex, out var value);
			return value;
		}

		internal void Update()
		{
			SharedTextureSlot.ProcessDeferredNativeReleases();
			TryEnsureMessenger();
			TryPublishRendererDevice();
			Action result;
			while (_mainThreadActions.TryDequeue(out result))
			{
				try
				{
					result();
				}
				catch (Exception ex)
				{
					SharedTextureBridgePlugin.LogError("IPC action failed", ex);
				}
			}
			for (int num = _pendingBinds.Count - 1; num >= 0; num--)
			{
				var (num2, num3, sharedTextureSlot) = _pendingBinds[num];
				if (!_activeGenerations.TryGetValue(num2, out var value) || value != num3)
				{
					_pendingBinds.RemoveAt(num);
					continue;
				}
				bool flag;
				try
				{
					flag = sharedTextureSlot.TryBind();
				}
				catch (Exception ex2)
				{
					SharedTextureBridgePlugin.LogError($"Pending TryBind threw slot={num2}", ex2);
					continue;
				}
				if (flag)
				{
					_pendingBinds.RemoveAt(num);
					WriteRunning(num2, num3, sharedTextureSlot);
					SharedTextureBridgePlugin.LogInfo($"[SharedTextureBridge] Slot {num2} gen={num3} bound: {sharedTextureSlot.Width}x{sharedTextureSlot.Height}");
				}
			}
		}

		private void TryPublishRendererDevice()
		{
			if (_rendererDevicePublished || _messenger == null)
			{
				return;
			}
			try
			{
				if (UnityD3D11Device.Initialize(_log) && UnityD3D11Device.HasAdapterInfo)
				{
					_messenger.SendObject<SharedTextureRendererDeviceMessage>("RendererDevice", new SharedTextureRendererDeviceMessage
					{
						AdapterLuid = UnityD3D11Device.AdapterLuid,
						VendorId = UnityD3D11Device.AdapterVendorId,
						Description = UnityD3D11Device.AdapterDescription
					});
					_rendererDevicePublished = true;
					SharedTextureBridgePlugin.LogInfo($"[SharedTextureBridge] Published renderer adapter '{UnityD3D11Device.AdapterDescription}' VendorId=0x{UnityD3D11Device.AdapterVendorId:X4} LUID=0x{UnityD3D11Device.AdapterLuid:X16}");
				}
			}
			catch (Exception ex)
			{
				SharedTextureBridgePlugin.LogWarning("[SharedTextureBridge] Failed to publish renderer adapter: " + ex.Message);
			}
		}

		private void TryEnsureMessenger()
		{
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Expected O, but got Unknown
			if (_messenger != null)
			{
				return;
			}
			_connectRetryTimer += Time.unscaledDeltaTime;
			_connectLogTimer += Time.unscaledDeltaTime;
			if (_connectLogTimer >= 5f)
			{
				_connectLogTimer = 0f;
				SharedTextureBridgePlugin.LogInfo("[SharedTextureBridge] Waiting for InterprocessLib queue " + SharedTextureBridgeProtocol.QueueName);
			}
			if (_connectRetryTimer < 1f)
			{
				return;
			}
			_connectRetryTimer = 0f;
			try
			{
				SharedTextureBridgePlugin.LogInfo("[SharedTextureBridge] Creating Messenger");
				Messenger.OnWarning += OnWarning;
				Messenger.OnFailure += OnFailure;
				_messenger = new Messenger(SharedTextureBridgeProtocol.OwnerId, false, SharedTextureBridgeProtocol.QueueName, (IMemoryPackerEntityPool)(object)SimpleMemoryPackerPool.Instance, 1048576L);
				RegisterMessages();
				SharedTextureBridgePlugin.LogInfo("Opened InterprocessLib queue: " + SharedTextureBridgeProtocol.QueueName);
			}
			catch (Exception ex)
			{
				Messenger.OnWarning -= OnWarning;
				Messenger.OnFailure -= OnFailure;
				Messenger messenger = _messenger;
				if (messenger != null)
				{
					messenger.Dispose();
				}
				_messenger = null;
				SharedTextureBridgePlugin.LogWarning("InterprocessLib queue not ready: " + ex.GetType().Name + ": " + ex.Message);
			}
		}

		private void RegisterMessages()
		{
			_messenger.ReceiveObject<SharedTextureStartMessage>("Start", (Action<SharedTextureStartMessage>)delegate(SharedTextureStartMessage msg)
			{
				try
				{
					if (msg != null)
					{
						SharedTextureBridgePlugin.LogInfo($"[SharedTextureBridge] Received Start slot={msg.SlotId} gen={msg.Generation} name={msg.SharedTextureName} shared=0x{msg.SharedTextureHandle:X} {msg.SharedTextureWidth}x{msg.SharedTextureHeight}");
						_mainThreadActions.Enqueue(delegate
						{
							StartSharedTexture(msg.SlotId, msg.Generation, msg.SharedTextureHandle, msg.SharedTextureName, msg.SharedTextureWidth, msg.SharedTextureHeight);
						});
					}
				}
				catch (Exception ex2)
				{
					SharedTextureBridgePlugin.LogError("[SharedTextureBridge] Start callback failed", ex2);
				}
			});
			_messenger.ReceiveObject<SharedTextureStopMessage>("Stop", (Action<SharedTextureStopMessage>)delegate(SharedTextureStopMessage msg)
			{
				try
				{
					if (msg != null)
					{
						SharedTextureBridgePlugin.LogInfo($"[SharedTextureBridge] Received Stop slot={msg.SlotId} gen={msg.Generation}");
						_mainThreadActions.Enqueue(delegate
						{
							StopSharedTexture(msg.SlotId, msg.Generation, sendStopped: true);
						});
					}
				}
				catch (Exception ex)
				{
					SharedTextureBridgePlugin.LogError("[SharedTextureBridge] Stop callback failed", ex);
				}
			});
			_messenger.ReceiveObject<SharedTextureRunningMessage>("Running", (Action<SharedTextureRunningMessage>)delegate
			{
			});
			_messenger.ReceiveObject<SharedTextureStoppedMessage>("Stopped", (Action<SharedTextureStoppedMessage>)delegate
			{
			});
			_messenger.ReceiveObject<SharedTextureRendererDeviceMessage>("RendererDevice", (Action<SharedTextureRendererDeviceMessage>)delegate
			{
			});
		}

		private void StartSharedTexture(int slot, int generation, long sharedTextureHandleRaw, string sharedTextureName, int sharedTextureWidth, int sharedTextureHeight)
		{
			if (_activeSlots.ContainsKey(slot))
			{
				StopSharedTexture(slot, _activeGenerations.TryGetValue(slot, out var value) ? value : 0, sendStopped: false);
			}
			IntPtr intPtr = new IntPtr(sharedTextureHandleRaw);
			SharedTextureBridgePlugin.LogInfo($"Starting shared texture slot={slot} gen={generation} name={sharedTextureName} shared=0x{sharedTextureHandleRaw:X} {sharedTextureWidth}x{sharedTextureHeight}");
			if (intPtr == IntPtr.Zero || sharedTextureWidth <= 0 || sharedTextureHeight <= 0)
			{
				SharedTextureBridgePlugin.LogWarning($"Shared texture start ignored slot={slot} gen={generation}: missing handle or size");
				return;
			}
			SharedTextureSlot sharedTextureSlot;
			try
			{
				sharedTextureSlot = new SharedTextureSlot(intPtr, sharedTextureWidth, sharedTextureHeight, _log);
				_activeSlots[slot] = sharedTextureSlot;
				_activeGenerations[slot] = generation;
				_bridgeIndexToSlot[10000 + slot] = sharedTextureSlot;
				SharedTextureBridgePlugin.LogInfo($"Registered bridge index={10000 + slot} slot={slot} gen={generation}");
			}
			catch (Exception ex)
			{
				SharedTextureBridgePlugin.LogError($"Shared texture slot construction failed slot={slot} gen={generation}", ex);
				return;
			}
			bool flag;
			try
			{
				flag = sharedTextureSlot.TryBind();
			}
			catch (Exception ex2)
			{
				SharedTextureBridgePlugin.LogError($"Initial TryBind threw slot={slot} gen={generation}", ex2);
				return;
			}
			if (flag)
			{
				WriteRunning(slot, generation, sharedTextureSlot);
				return;
			}
			SharedTextureBridgePlugin.LogWarning($"Initial TryBind failed slot={slot} gen={generation}; adding pending bind");
			_pendingBinds.Add((slot, generation, sharedTextureSlot));
		}

		private void StopSharedTexture(int slot, int generation, bool sendStopped)
		{
			if (!_activeSlots.ContainsKey(slot))
			{
				if (sendStopped)
				{
					WriteStopped(slot, generation);
				}
				return;
			}
			if (_activeGenerations.TryGetValue(slot, out var value) && value != generation)
			{
				SharedTextureBridgePlugin.LogWarning($"Ignoring stale shared texture stop slot={slot} gen={generation} active={value}");
				return;
			}
			SharedTextureBridgePlugin.LogInfo($"Stopping shared texture slot={slot} gen={generation}");
			_bridgeIndexToSlot.TryRemove(10000 + slot, out var _);
			SharedTextureBridgePlugin.LogInfo($"[SharedTextureBridge] Removed bridge index for slot={slot}");
			try
			{
				_activeSlots[slot].Dispose();
				SharedTextureBridgePlugin.LogInfo($"[SharedTextureBridge] Slot dispose completed slot={slot}");
			}
			catch (Exception ex)
			{
				SharedTextureBridgePlugin.LogError($"[SharedTextureBridge] Slot dispose failed slot={slot}", ex);
			}
			_activeSlots.Remove(slot);
			_activeGenerations.Remove(slot);
			_pendingBinds.RemoveAll(((int slot, int generation, SharedTextureSlot textureSlot) p) => p.slot == slot);
			if (sendStopped)
			{
				WriteStopped(slot, generation);
			}
			SharedTextureBridgePlugin.LogInfo($"[SharedTextureBridge] Stop complete slot={slot}");
		}

		private void WriteRunning(int slot, int generation, SharedTextureSlot textureSlot)
		{
			try
			{
				Messenger messenger = _messenger;
				if (messenger != null)
				{
					messenger.SendObject<SharedTextureRunningMessage>("Running", new SharedTextureRunningMessage
					{
						SlotId = slot,
						Generation = generation,
						Width = textureSlot.Width,
						Height = textureSlot.Height
					});
				}
			}
			catch (Exception ex)
			{
				SharedTextureBridgePlugin.LogWarning($"Failed to send running ack for slot {slot}: {ex.Message}");
			}
			SharedTextureBridgePlugin.LogInfo($"Shared texture slot={slot} gen={generation} running: {textureSlot.Width}x{textureSlot.Height}");
		}

		private void WriteStopped(int slot, int generation)
		{
			try
			{
				Messenger messenger = _messenger;
				if (messenger != null)
				{
					messenger.SendObject<SharedTextureStoppedMessage>("Stopped", new SharedTextureStoppedMessage
					{
						SlotId = slot,
						Generation = generation
					});
				}
			}
			catch (Exception ex)
			{
				SharedTextureBridgePlugin.LogWarning($"Failed to send stopped ack for slot {slot} gen={generation}: {ex.Message}");
			}
			SharedTextureBridgePlugin.LogInfo($"Shared texture slot={slot} gen={generation} stopped");
		}

		private void OnWarning(string message)
		{
			SharedTextureBridgePlugin.LogWarning("[InterprocessLib] " + message);
		}

		private void OnFailure(Exception ex)
		{
			SharedTextureBridgePlugin.LogError("[InterprocessLib]", ex);
		}

		public void Dispose()
		{
			SharedTextureBridgePlugin.LogInfo("[SharedTextureBridge] Disposing");
			foreach (KeyValuePair<int, SharedTextureSlot> activeSlot in _activeSlots)
			{
				try
				{
					SharedTextureBridgePlugin.LogInfo($"[SharedTextureBridge] Disposing slot={activeSlot.Key}");
					activeSlot.Value.Dispose();
				}
				catch (Exception ex)
				{
					SharedTextureBridgePlugin.LogError($"[SharedTextureBridge] Slot dispose failed during bridge dispose slot={activeSlot.Key}", ex);
				}
			}
			_activeSlots.Clear();
			_activeGenerations.Clear();
			_bridgeIndexToSlot.Clear();
			_pendingBinds.Clear();
			try
			{
				SharedTextureBridgePlugin.LogInfo("[SharedTextureBridge] Messenger.Dispose START");
				Messenger messenger = _messenger;
				if (messenger != null)
				{
					messenger.Dispose();
				}
				SharedTextureBridgePlugin.LogInfo("[SharedTextureBridge] Messenger.Dispose DONE");
			}
			catch (Exception ex2)
			{
				SharedTextureBridgePlugin.LogError("[SharedTextureBridge] Messenger.Dispose failed", ex2);
			}
			_messenger = null;
			Messenger.OnWarning -= OnWarning;
			Messenger.OnFailure -= OnFailure;
			SharedTextureBridgePlugin.LogInfo("[SharedTextureBridge] Disposed");
		}
	}
	[BepInPlugin("net.desktopbuddy.sharedtexturebridge", "DesktopBuddySharedTextureBridge", "1.0.19")]
	public class SharedTextureBridgePlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private SharedTextureBridge _bridge;

		private void Awake()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			LogInfo("DesktopBuddySharedTextureBridge starting...");
			try
			{
				new Harmony("net.desktopbuddy.sharedtexturebridge").PatchAll();
				LogInfo("Harmony patches applied");
			}
			catch (Exception ex)
			{
				LogError("Harmony PatchAll failed", ex);
				throw;
			}
			try
			{
				_bridge = new SharedTextureBridge(Log);
				LogInfo("SharedTextureBridge created");
			}
			catch (Exception ex2)
			{
				LogError("SharedTextureBridge creation failed", ex2);
				throw;
			}
			LogInfo("DesktopBuddySharedTextureBridge ready");
		}

		private void Update()
		{
			try
			{
				_bridge?.Update();
			}
			catch (Exception ex)
			{
				LogError("Update failed", ex);
			}
		}

		private void OnDestroy()
		{
			LogInfo("DesktopBuddySharedTextureBridge OnDestroy START");
			try
			{
				_bridge?.Dispose();
				LogInfo("SharedTextureBridge disposed");
			}
			catch (Exception ex)
			{
				LogError("SharedTextureBridge dispose failed", ex);
			}
			try
			{
				UnityD3D11Device.Dispose();
				LogInfo("UnityD3D11Device disposed");
			}
			catch (Exception ex2)
			{
				LogError("UnityD3D11Device dispose failed", ex2);
			}
			LogInfo("DesktopBuddySharedTextureBridge OnDestroy DONE");
		}

		internal static void LogInfo(string message)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)message);
			}
		}

		internal static void LogWarning(string message)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogWarning((object)message);
			}
		}

		internal static void LogError(string message, Exception ex)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogError((object)$"{message}: {ex}");
			}
		}
	}
	[HarmonyPatch(typeof(DisplayDriver), "TryGetDisplayTexture")]
	internal static class SharedTextureIndexPatch
	{
		private static bool Prefix(int index, ref IDisplayTextureSource __result)
		{
			try
			{
				if (index < 10000)
				{
					return true;
				}
				SharedTextureSlot slotForBridgeIndex = SharedTextureBridge.GetSlotForBridgeIndex(index);
				__result = (IDisplayTextureSource)(object)slotForBridgeIndex;
				return false;
			}
			catch (Exception ex)
			{
				SharedTextureBridgePlugin.LogError($"[SharedTextureIndexPatch] Prefix failed index={index}", ex);
				__result = null;
				return false;
			}
		}
	}
	internal sealed class SharedTextureSlot : IDisplayTextureSource, IDisposable
	{
		private struct DeferredNativeRelease
		{
			public IntPtr ShaderResourceView;

			public IntPtr OpenedTexture;

			public long SharedHandle;

			public int FramesRemaining;
		}

		private struct D3D11_TEX2D_SRV
		{
			public uint MostDetailedMip;

			public uint MipLevels;
		}

		private struct D3D11_SHADER_RESOURCE_VIEW_DESC
		{
			public uint Format;

			public uint ViewDimension;

			public D3D11_TEX2D_SRV Texture2D;
		}

		private const int ID3D11Device_OpenSharedResource = 28;

		private const int ID3D11Device_CreateShaderResourceView = 7;

		private const uint DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91u;

		private const uint D3D11_SRV_DIMENSION_TEXTURE2D = 4u;

		private static readonly Guid Texture2DGuid = new Guid("6f15aaf2-d208-4e89-9ab4-489535d34f9c");

		private const int DeferredReleaseFrames = 3;

		private static readonly ConcurrentQueue<DeferredNativeRelease> DeferredReleases = new ConcurrentQueue<DeferredNativeRelease>();

		private readonly ManualLogSource _log;

		private readonly IntPtr _sharedHandle;

		private readonly HashSet<Action> _requests = new HashSet<Action>();

		private IntPtr _openedTexture;

		private IntPtr _shaderResourceView;

		private Texture2D _unityTexture;

		private bool _started;

		private bool _disposed;

		public Texture UnityTexture => (Texture)(object)_unityTexture;

		public int Width { get; }

		public int Height { get; }

		public int RequestCount => _requests.Count;

		public bool IsValid
		{
			get
			{
				if (!_disposed && _started)
				{
					return (Object)(object)_unityTexture != (Object)null;
				}
				return false;
			}
		}

		public string SourceName => "SharedTexture";

		internal SharedTextureSlot(IntPtr sharedHandle, int width, int height, ManualLogSource log)
		{
			_sharedHandle = sharedHandle;
			Width = width;
			Height = height;
			_log = log;
			SharedTextureBridgePlugin.LogInfo($"[SharedTexture] Constructed handle=0x{_sharedHandle.ToInt64():X} {Width}x{Height}");
		}

		public bool TryBind()
		{
			if (_started)
			{
				return true;
			}
			if (_disposed)
			{
				return false;
			}
			if (_sharedHandle == IntPtr.Zero || Width <= 0 || Height <= 0)
			{
				return false;
			}
			if (!UnityD3D11Device.IsReady && !UnityD3D11Device.Initialize(_log))
			{
				SharedTextureBridgePlugin.LogWarning("[SharedTexture] Renderer D3D device is not ready");
				return false;
			}
			try
			{
				OpenSharedTexture();
				CreateShaderResourceView();
				_unityTexture = Texture2D.CreateExternalTexture(Width, Height, (TextureFormat)14, false, false, _shaderResourceView);
				Texture2D unityTexture = _unityTexture;
				IntPtr sharedHandle = _sharedHandle;
				((Object)unityTexture).name = $"DesktopBuddy SharedTexture 0x{sharedHandle.ToInt64():X}";
				((Texture)_unityTexture).wrapMode = (TextureWrapMode)1;
				_started = true;
				object[] array = new object[5];
				sharedHandle = _sharedHandle;
				array[0] = sharedHandle.ToInt64();
				array[1] = _openedTexture.ToInt64();
				array[2] = _shaderResourceView.ToInt64();
				array[3] = Width;
				array[4] = Height;
				SharedTextureBridgePlugin.LogInfo(string.Format("[SharedTexture] Bound handle=0x{0:X} texture=0x{1:X} srv=0x{2:X} {3}x{4}", array));
				NotifyCallbacks();
				return true;
			}
			catch (Exception ex)
			{
				SharedTextureBridgePlugin.LogError("[SharedTexture] TryBind failed", ex);
				Dispose();
				return false;
			}
		}

		public void RegisterRequest(Action onTextureChanged)
		{
			try
			{
				if (onTextureChanged != null)
				{
					_requests.Add(onTextureChanged);
				}
				if ((Object)(object)_unityTexture != (Object)null)
				{
					onTextureChanged?.Invoke();
				}
			}
			catch (Exception ex)
			{
				SharedTextureBridgePlugin.LogError("[SharedTexture] RegisterRequest callback failed", ex);
			}
		}

		public void UnregisterRequest(Action onTextureChanged)
		{
			try
			{
				if (onTextureChanged != null)
				{
					_requests.Remove(onTextureChanged);
				}
			}
			catch (Exception ex)
			{
				SharedTextureBridgePlugin.LogError("[SharedTexture] UnregisterRequest failed", ex);
			}
		}

		public void Dispose()
		{
			object[] array = new object[7];
			IntPtr sharedHandle = _sharedHandle;
			array[0] = sharedHandle.ToInt64();
			array[1] = _disposed;
			array[2] = _started;
			array[3] = (Object)(object)_unityTexture != (Object)null;
			array[4] = _shaderResourceView.ToInt64();
			array[5] = _openedTexture.ToInt64();
			array[6] = _requests.Count;
			SharedTextureBridgePlugin.LogInfo(string.Format("[SharedTexture] Dispose ENTER handle=0x{0:X} disposed={1} started={2} unityTexture={3} srv=0x{4:X} texture=0x{5:X} requests={6}", array));
			if (!_disposed)
			{
				_disposed = true;
				if ((Object)(object)_unityTexture != (Object)null)
				{
					sharedHandle = _sharedHandle;
					SharedTextureBridgePlugin.LogInfo($"[SharedTexture] Unity texture Destroy START handle=0x{sharedHandle.ToInt64():X}");
					Object.Destroy((Object)(object)_unityTexture);
					_unityTexture = null;
					sharedHandle = _sharedHandle;
					SharedTextureBridgePlugin.LogInfo($"[SharedTexture] Unity texture Destroy queued handle=0x{sharedHandle.ToInt64():X}");
				}
				if (_shaderResourceView != IntPtr.Zero || _openedTexture != IntPtr.Zero)
				{
					ConcurrentQueue<DeferredNativeRelease> deferredReleases = DeferredReleases;
					DeferredNativeRelease item = new DeferredNativeRelease
					{
						ShaderResourceView = _shaderResourceView,
						OpenedTexture = _openedTexture
					};
					sharedHandle = _sharedHandle;
					item.SharedHandle = sharedHandle.ToInt64();
					item.FramesRemaining = 3;
					deferredReleases.Enqueue(item);
					object[] array2 = new object[4];
					sharedHandle = _sharedHandle;
					array2[0] = sharedHandle.ToInt64();
					array2[1] = 3;
					array2[2] = _shaderResourceView.ToInt64();
					array2[3] = _openedTexture.ToInt64();
					SharedTextureBridgePlugin.LogInfo(string.Format("[SharedTexture] Deferred native release queued handle=0x{0:X} frames={1} srv=0x{2:X} texture=0x{3:X}", array2));
					_shaderResourceView = IntPtr.Zero;
					_openedTexture = IntPtr.Zero;
				}
				_requests.Clear();
				sharedHandle = _sharedHandle;
				SharedTextureBridgePlugin.LogInfo($"[SharedTexture] Disposed handle=0x{sharedHandle.ToInt64():X}");
			}
		}

		internal static void ProcessDeferredNativeReleases()
		{
			int count = DeferredReleases.Count;
			for (int i = 0; i < count; i++)
			{
				if (!DeferredReleases.TryDequeue(out var result))
				{
					break;
				}
				result.FramesRemaining--;
				if (result.FramesRemaining > 0)
				{
					DeferredReleases.Enqueue(result);
					continue;
				}
				SharedTextureBridgePlugin.LogInfo($"[SharedTexture] Deferred native release START handle=0x{result.SharedHandle:X} srv=0x{result.ShaderResourceView.ToInt64():X} texture=0x{result.OpenedTexture.ToInt64():X}");
				try
				{
					if (result.ShaderResourceView != IntPtr.Zero)
					{
						Marshal.Release(result.ShaderResourceView);
					}
					if (result.OpenedTexture != IntPtr.Zero)
					{
						Marshal.Release(result.OpenedTexture);
					}
				}
				catch (Exception ex)
				{
					SharedTextureBridgePlugin.LogError("[SharedTexture] Deferred native release failed", ex);
				}
				SharedTextureBridgePlugin.LogInfo($"[SharedTexture] Deferred native release DONE handle=0x{result.SharedHandle:X}");
			}
		}

		private unsafe void OpenSharedTexture()
		{
			delegate* unmanaged[Stdcall]<IntPtr, IntPtr, Guid*, IntPtr*, int> delegate* = (delegate* unmanaged[Stdcall]<IntPtr, IntPtr, Guid*, IntPtr*, int>)(void*)(*(IntPtr*)((nint)(*(IntPtr*)(void*)UnityD3D11Device.D3dDevice) + (nint)28 * (nint)sizeof(IntPtr)));
			Guid texture2DGuid = Texture2DGuid;
			IntPtr intPtr = default(IntPtr);
			int num = delegate*(UnityD3D11Device.D3dDevice, _sharedHandle, &texture2DGuid, &intPtr);
			if (num < 0 || intPtr == IntPtr.Zero)
			{
				object arg = num;
				IntPtr sharedHandle = _sharedHandle;
				throw new InvalidOperationException($"OpenSharedResource failed hr=0x{arg:X8} handle=0x{sharedHandle.ToInt64():X}");
			}
			_openedTexture = intPtr;
		}

		private unsafe void CreateShaderResourceView()
		{
			D3D11_SHADER_RESOURCE_VIEW_DESC d3D11_SHADER_RESOURCE_VIEW_DESC = default(D3D11_SHADER_RESOURCE_VIEW_DESC);
			d3D11_SHADER_RESOURCE_VIEW_DESC.Format = 91u;
			d3D11_SHADER_RESOURCE_VIEW_DESC.ViewDimension = 4u;
			d3D11_SHADER_RESOURCE_VIEW_DESC.Texture2D = new D3D11_TEX2D_SRV
			{
				MostDetailedMip = 0u,
				MipLevels = 1u
			};
			D3D11_SHADER_RESOURCE_VIEW_DESC d3D11_SHADER_RESOURCE_VIEW_DESC2 = d3D11_SHADER_RESOURCE_VIEW_DESC;
			IntPtr intPtr = default(IntPtr);
			int num = ((delegate* unmanaged[Stdcall]<IntPtr, IntPtr, D3D11_SHADER_RESOURCE_VIEW_DESC*, IntPtr*, int>)(void*)(*(IntPtr*)((nint)(*(IntPtr*)(void*)UnityD3D11Device.D3dDevice) + (nint)7 * (nint)sizeof(IntPtr))))(UnityD3D11Device.D3dDevice, _openedTexture, &d3D11_SHADER_RESOURCE_VIEW_DESC2, &intPtr);
			if (num < 0 || intPtr == IntPtr.Zero)
			{
				throw new InvalidOperationException($"CreateShaderResourceView failed hr=0x{num:X8} texture=0x{_openedTexture.ToInt64():X}");
			}
			_shaderResourceView = intPtr;
		}

		private void NotifyCallbacks()
		{
			foreach (Action request in _requests)
			{
				try
				{
					request?.Invoke();
				}
				catch (Exception ex)
				{
					ManualLogSource log = _log;
					if (log != null)
					{
						log.LogWarning((object)("[SharedTexture] Callback error: " + ex.Message));
					}
				}
			}
		}
	}
	internal static class UnityD3D11Device
	{
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		private struct DXGI_ADAPTER_DESC
		{
			public unsafe fixed char Description[128];

			public uint VendorId;

			public uint DeviceId;

			public uint SubSysId;

			public uint Revision;

			public UIntPtr DedicatedVideoMemory;

			public UIntPtr DedicatedSystemMemory;

			public UIntPtr SharedSystemMemory;

			public long AdapterLuid;
		}

		private const int ID3D11Resource_GetDevice = 3;

		private const int IDXGIDevice_GetAdapter = 7;

		private const int IDXGIAdapter_GetDesc = 8;

		private static readonly object Lock = new object();

		private static IntPtr _d3dDevice;

		private static bool _initialized;

		private static long _adapterLuid;

		private static int _adapterVendorId;

		private static string _adapterDescription;

		internal static IntPtr D3dDevice => _d3dDevice;

		internal static bool IsReady
		{
			get
			{
				if (_initialized)
				{
					return _d3dDevice != IntPtr.Zero;
				}
				return false;
			}
		}

		internal static long AdapterLuid => _adapterLuid;

		internal static int AdapterVendorId => _adapterVendorId;

		internal static string AdapterDescription => _adapterDescription;

		internal static bool HasAdapterInfo => _adapterLuid != 0;

		internal unsafe static bool Initialize(ManualLogSource log)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			Info(log, "[UnityD3D11] Initialize entered");
			if (IsReady)
			{
				return true;
			}
			lock (Lock)
			{
				Info(log, "[UnityD3D11] Initialize lock entered");
				if (IsReady)
				{
					return true;
				}
				try
				{
					Texture2D val = null;
					Info(log, "[UnityD3D11] Creating Unity probe texture");
					try
					{
						val = new Texture2D(1, 1, (TextureFormat)14, false, true);
						Info(log, "[UnityD3D11] Applying Unity probe texture");
						val.Apply(false, true);
						Info(log, "[UnityD3D11] Getting native texture pointer");
						IntPtr nativeTexturePtr = ((Texture)val).GetNativeTexturePtr();
						if (nativeTexturePtr == IntPtr.Zero)
						{
							Error(log, "[UnityD3D11] Unity probe texture native pointer is null");
							return false;
						}
						Info(log, $"[UnityD3D11] Probe native texture=0x{nativeTexturePtr.ToInt64():X}");
						Info(log, "[UnityD3D11] Reading D3D resource vtable");
						delegate* unmanaged[Stdcall]<IntPtr, IntPtr*, void> delegate* = (delegate* unmanaged[Stdcall]<IntPtr, IntPtr*, void>)(void*)(*(IntPtr*)((nint)(*(IntPtr*)(void*)nativeTexturePtr) + (nint)3 * (nint)sizeof(IntPtr)));
						Info(log, "[UnityD3D11] Calling ID3D11Resource.GetDevice");
						IntPtr d3dDevice = default(IntPtr);
						delegate*(nativeTexturePtr, &d3dDevice);
						_d3dDevice = d3dDevice;
					}
					finally
					{
						if ((Object)(object)val != (Object)null)
						{
							Object.Destroy((Object)(object)val);
						}
					}
					if (_d3dDevice == IntPtr.Zero)
					{
						Error(log, "[UnityD3D11] ID3D11Resource.GetDevice returned null");
						return false;
					}
					Info(log, $"[UnityD3D11] D3D device=0x{_d3dDevice.ToInt64():X}");
					TryReadAdapterInfo(log);
					_initialized = true;
					Info(log, $"[UnityD3D11] Unity D3D11 device ready device=0x{_d3dDevice.ToInt64():X} adapter='{_adapterDescription}' vendor=0x{_adapterVendorId:X4} LUID=0x{_adapterLuid:X16}");
					return true;
				}
				catch (Exception arg)
				{
					if (log != null)
					{
						log.LogError((object)$"[UnityD3D11] Renderer device init failed: {arg}");
					}
					return false;
				}
			}
		}

		private unsafe static void TryReadAdapterInfo(ManualLogSource log)
		{
			Guid iid = new Guid("54ec77fa-1377-44e6-8c32-88fd5f44c84c");
			IntPtr ppv = IntPtr.Zero;
			IntPtr zero = IntPtr.Zero;
			try
			{
				int num = Marshal.QueryInterface(_d3dDevice, ref iid, out ppv);
				if (num < 0 || ppv == IntPtr.Zero)
				{
					Info(log, $"[UnityD3D11] IDXGIDevice QueryInterface failed hr=0x{num:X8}");
					return;
				}
				num = ((delegate* unmanaged[Stdcall]<IntPtr, IntPtr*, int>)(void*)(*(IntPtr*)((nint)(*(IntPtr*)(void*)ppv) + (nint)7 * (nint)sizeof(IntPtr))))(ppv, &zero);
				if (num < 0 || zero == IntPtr.Zero)
				{
					Info(log, $"[UnityD3D11] IDXGIDevice.GetAdapter failed hr=0x{num:X8}");
					return;
				}
				DXGI_ADAPTER_DESC dXGI_ADAPTER_DESC = default(DXGI_ADAPTER_DESC);
				num = ((delegate* unmanaged[Stdcall]<IntPtr, DXGI_ADAPTER_DESC*, int>)(void*)(*(IntPtr*)((nint)(*(IntPtr*)(void*)zero) + (nint)8 * (nint)sizeof(IntPtr))))(zero, &dXGI_ADAPTER_DESC);
				if (num < 0)
				{
					Info(log, $"[UnityD3D11] IDXGIAdapter.GetDesc failed hr=0x{num:X8}");
					return;
				}
				_adapterLuid = dXGI_ADAPTER_DESC.AdapterLuid;
				_adapterVendorId = (int)dXGI_ADAPTER_DESC.VendorId;
				_adapterDescription = new string(dXGI_ADAPTER_DESC.Description).TrimEnd(new char[1]);
				Info(log, $"[UnityD3D11] Adapter '{_adapterDescription}' VendorId=0x{dXGI_ADAPTER_DESC.VendorId:X4} LUID=0x{dXGI_ADAPTER_DESC.AdapterLuid:X16}");
			}
			catch (Exception ex)
			{
				if (log != null)
				{
					log.LogWarning((object)("[UnityD3D11] Failed to read adapter info: " + ex.Message));
				}
			}
			finally
			{
				if (zero != IntPtr.Zero)
				{
					Marshal.Release(zero);
				}
				if (ppv != IntPtr.Zero)
				{
					Marshal.Release(ppv);
				}
			}
		}

		internal static void Dispose()
		{
			SharedTextureBridgePlugin.LogInfo($"[UnityD3D11] Dispose ENTER initialized={_initialized} device=0x{_d3dDevice.ToInt64():X}");
			lock (Lock)
			{
				SharedTextureBridgePlugin.LogInfo("[UnityD3D11] Dispose lock entered");
				if (_d3dDevice != IntPtr.Zero)
				{
					try
					{
						Marshal.Release(_d3dDevice);
					}
					catch (Exception ex)
					{
						SharedTextureBridgePlugin.LogError("[UnityD3D11] Device release failed", ex);
					}
					_d3dDevice = IntPtr.Zero;
				}
				_initialized = false;
				_adapterLuid = 0L;
				_adapterVendorId = 0;
				_adapterDescription = null;
			}
			SharedTextureBridgePlugin.LogInfo("[UnityD3D11] Dispose EXIT");
		}

		private static void Info(ManualLogSource log, string message)
		{
			if (log != null)
			{
				log.LogInfo((object)message);
			}
		}

		private static void Error(ManualLogSource log, string message)
		{
			if (log != null)
			{
				log.LogError((object)message);
			}
		}
	}
	internal static class BridgeVersionInfo
	{
		internal const string Version = "1.0.19";
	}
}