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+8e666fb408568fd98ed9f9ed0dd7d1aca84b97f3")]
[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
{
public const string OwnerId = "DesktopBuddy.SharedTexture";
public const string QueueName = "DesktopBuddy.SharedTexture";
public const string StartMessageId = "Start";
public const string StopMessageId = "Stop";
public const string RunningMessageId = "Running";
public const int MaxTextureSlots = 4096;
public const int MagicIndexBase = 10000;
}
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 long SharedTextureHandle;
public int SharedTextureWidth;
public int SharedTextureHeight;
public void Pack(ref MemoryPacker packer)
{
((MemoryPacker)(ref packer)).Write<int>(SlotId);
((MemoryPacker)(ref packer)).Write<long>(SharedTextureHandle);
((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<long>(ref SharedTextureHandle);
((MemoryUnpacker)(ref unpacker)).Read<int>(ref SharedTextureWidth);
((MemoryUnpacker)(ref unpacker)).Read<int>(ref SharedTextureHeight);
}
}
internal sealed class SharedTextureStopMessage : IMemoryPackable
{
public int SlotId;
public void Pack(ref MemoryPacker packer)
{
((MemoryPacker)(ref packer)).Write<int>(SlotId);
}
public void Unpack(ref MemoryUnpacker unpacker)
{
((MemoryUnpacker)(ref unpacker)).Read<int>(ref SlotId);
}
}
internal sealed class SharedTextureRunningMessage : IMemoryPackable
{
public int SlotId;
public int Width;
public int Height;
public void Pack(ref MemoryPacker packer)
{
((MemoryPacker)(ref packer)).Write<int>(SlotId);
((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 Width);
((MemoryUnpacker)(ref unpacker)).Read<int>(ref Height);
}
}
}
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 static readonly ConcurrentDictionary<int, SharedTextureSlot> _bridgeIndexToSlot = new ConcurrentDictionary<int, SharedTextureSlot>();
private readonly List<(int slot, SharedTextureSlot textureSlot)> _pendingBinds = new List<(int, SharedTextureSlot)>();
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();
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, sharedTextureSlot) = _pendingBinds[num];
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, sharedTextureSlot);
SharedTextureBridgePlugin.LogInfo($"[SharedTextureBridge] Slot {num2} bound: {sharedTextureSlot.Width}x{sharedTextureSlot.Height}");
}
}
}
private void TryEnsureMessenger()
{
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: 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 DesktopBuddy.SharedTexture");
}
if (_connectRetryTimer < 1f)
{
return;
}
_connectRetryTimer = 0f;
try
{
SharedTextureBridgePlugin.LogInfo("[SharedTextureBridge] Creating Messenger");
Messenger.OnWarning += OnWarning;
Messenger.OnFailure += OnFailure;
_messenger = new Messenger("DesktopBuddy.SharedTexture", false, "DesktopBuddy.SharedTexture", (IMemoryPackerEntityPool)(object)SimpleMemoryPackerPool.Instance, 1048576L);
_messenger.ReceiveObject<SharedTextureStartMessage>("Start", (Action<SharedTextureStartMessage>)delegate(SharedTextureStartMessage msg)
{
try
{
if (msg != null)
{
SharedTextureBridgePlugin.LogInfo($"[SharedTextureBridge] Received Start slot={msg.SlotId} shared=0x{msg.SharedTextureHandle:X} {msg.SharedTextureWidth}x{msg.SharedTextureHeight}");
_mainThreadActions.Enqueue(delegate
{
StartSharedTexture(msg.SlotId, msg.SharedTextureHandle, msg.SharedTextureWidth, msg.SharedTextureHeight);
});
}
}
catch (Exception ex3)
{
SharedTextureBridgePlugin.LogError("[SharedTextureBridge] Start callback failed", ex3);
}
});
_messenger.ReceiveObject<SharedTextureStopMessage>("Stop", (Action<SharedTextureStopMessage>)delegate(SharedTextureStopMessage msg)
{
try
{
if (msg != null)
{
SharedTextureBridgePlugin.LogInfo($"[SharedTextureBridge] Received Stop slot={msg.SlotId}");
_mainThreadActions.Enqueue(delegate
{
StopSharedTexture(msg.SlotId);
});
}
}
catch (Exception ex2)
{
SharedTextureBridgePlugin.LogError("[SharedTextureBridge] Stop callback failed", ex2);
}
});
SharedTextureBridgePlugin.LogInfo("Opened InterprocessLib queue: DesktopBuddy.SharedTexture");
}
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 StartSharedTexture(int slot, long sharedTextureHandleRaw, int sharedTextureWidth, int sharedTextureHeight)
{
if (_activeSlots.ContainsKey(slot))
{
StopSharedTexture(slot);
}
IntPtr intPtr = new IntPtr(sharedTextureHandleRaw);
SharedTextureBridgePlugin.LogInfo($"Starting shared texture slot={slot} shared=0x{sharedTextureHandleRaw:X} {sharedTextureWidth}x{sharedTextureHeight}");
if (intPtr == IntPtr.Zero || sharedTextureWidth <= 0 || sharedTextureHeight <= 0)
{
SharedTextureBridgePlugin.LogWarning($"Shared texture start ignored slot={slot}: missing handle or size");
return;
}
SharedTextureSlot sharedTextureSlot;
try
{
sharedTextureSlot = new SharedTextureSlot(intPtr, sharedTextureWidth, sharedTextureHeight, _log);
_activeSlots[slot] = sharedTextureSlot;
_bridgeIndexToSlot[10000 + slot] = sharedTextureSlot;
SharedTextureBridgePlugin.LogInfo($"Registered bridge index={10000 + slot} slot={slot}");
}
catch (Exception ex)
{
SharedTextureBridgePlugin.LogError($"Shared texture slot construction failed slot={slot}", ex);
return;
}
bool flag;
try
{
flag = sharedTextureSlot.TryBind();
}
catch (Exception ex2)
{
SharedTextureBridgePlugin.LogError($"Initial TryBind threw slot={slot}", ex2);
return;
}
if (flag)
{
WriteRunning(slot, sharedTextureSlot);
return;
}
SharedTextureBridgePlugin.LogWarning($"Initial TryBind failed slot={slot}; adding pending bind");
_pendingBinds.Add((slot, sharedTextureSlot));
}
private void StopSharedTexture(int slot)
{
if (_activeSlots.ContainsKey(slot))
{
SharedTextureBridgePlugin.LogInfo($"Stopping shared texture slot={slot}");
_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);
_pendingBinds.RemoveAll(((int slot, SharedTextureSlot textureSlot) p) => p.slot == slot);
SharedTextureBridgePlugin.LogInfo($"[SharedTextureBridge] Stop complete slot={slot}");
}
}
private void WriteRunning(int slot, SharedTextureSlot textureSlot)
{
try
{
Messenger messenger = _messenger;
if (messenger != null)
{
messenger.SendObject<SharedTextureRunningMessage>("Running", new SharedTextureRunningMessage
{
SlotId = slot,
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} running: {textureSlot.Width}x{textureSlot.Height}");
}
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();
_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.17")]
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 void Postfix(int index, ref IDisplayTextureSource __result)
{
try
{
if (index >= 10000)
{
SharedTextureSlot slotForBridgeIndex = SharedTextureBridge.GetSlotForBridgeIndex(index);
if (slotForBridgeIndex != null)
{
__result = (IDisplayTextureSource)(object)slotForBridgeIndex;
}
}
}
catch (Exception ex)
{
SharedTextureBridgePlugin.LogError($"[SharedTextureIndexPatch] Postfix failed index={index}", ex);
}
}
}
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
{
private const int ID3D11Resource_GetDevice = 3;
private const int ID3D11Device_GetImmediateContext = 40;
private static readonly object Lock = new object();
private static Texture2D _probeTexture;
private static IntPtr _d3dDevice;
private static IntPtr _d3dContext;
private static bool _initialized;
internal static IntPtr D3dDevice => _d3dDevice;
internal static IntPtr D3dContext => _d3dContext;
internal static object ContextLock => Lock;
internal static bool IsReady
{
get
{
if (_initialized && _d3dDevice != IntPtr.Zero)
{
return _d3dContext != IntPtr.Zero;
}
return false;
}
}
internal unsafe static bool Initialize(ManualLogSource log)
{
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: 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
{
Info(log, "[UnityD3D11] Creating Unity probe texture");
_probeTexture = new Texture2D(1, 1, (TextureFormat)14, false, true);
Info(log, "[UnityD3D11] Applying Unity probe texture");
_probeTexture.Apply(false, true);
Info(log, "[UnityD3D11] Getting native texture pointer");
IntPtr nativeTexturePtr = ((Texture)_probeTexture).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;
if (_d3dDevice == IntPtr.Zero)
{
Error(log, "[UnityD3D11] ID3D11Resource.GetDevice returned null");
return false;
}
Info(log, $"[UnityD3D11] D3D device=0x{_d3dDevice.ToInt64():X}");
Info(log, "[UnityD3D11] Calling ID3D11Device.GetImmediateContext");
IntPtr d3dContext = default(IntPtr);
((delegate* unmanaged[Stdcall]<IntPtr, IntPtr*, void>)(void*)(*(IntPtr*)((nint)(*(IntPtr*)(void*)_d3dDevice) + (nint)40 * (nint)sizeof(IntPtr))))(_d3dDevice, &d3dContext);
_d3dContext = d3dContext;
Info(log, $"[UnityD3D11] D3D context=0x{_d3dContext.ToInt64():X}");
if (_d3dContext == IntPtr.Zero)
{
Error(log, "[UnityD3D11] ID3D11Device.GetImmediateContext returned null");
return false;
}
Info(log, "[UnityD3D11] Enabling multithread protection");
EnableMultithreadProtection(log);
_initialized = true;
Info(log, $"[UnityD3D11] Unity D3D11 device ready device=0x{_d3dDevice.ToInt64():X} context=0x{_d3dContext.ToInt64():X}");
return true;
}
catch (Exception arg)
{
if (log != null)
{
log.LogError((object)$"[UnityD3D11] Renderer device init failed: {arg}");
}
return false;
}
}
}
private unsafe static void EnableMultithreadProtection(ManualLogSource log)
{
Guid iid = new Guid("9B7E4E00-342C-4106-A19F-4F2704F689F0");
if (Marshal.QueryInterface(_d3dDevice, ref iid, out var ppv) < 0 || ppv == IntPtr.Zero)
{
Info(log, "[UnityD3D11] ID3D11Multithread unavailable");
return;
}
try
{
((delegate* unmanaged[Stdcall]<IntPtr, int, int*, int>)(void*)(*(IntPtr*)((nint)(*(IntPtr*)(void*)ppv) + (nint)4 * (nint)sizeof(IntPtr))))(ppv, 1, null);
Info(log, "[UnityD3D11] Unity D3D11 multithread protection enabled");
}
finally
{
Marshal.Release(ppv);
}
}
internal static void Dispose()
{
SharedTextureBridgePlugin.LogInfo($"[UnityD3D11] Dispose ENTER initialized={_initialized} device=0x{_d3dDevice.ToInt64():X} context=0x{_d3dContext.ToInt64():X} probe={(Object)(object)_probeTexture != (Object)null}");
lock (Lock)
{
SharedTextureBridgePlugin.LogInfo("[UnityD3D11] Dispose lock entered");
if (_d3dContext != IntPtr.Zero)
{
try
{
Marshal.Release(_d3dContext);
}
catch (Exception ex)
{
SharedTextureBridgePlugin.LogError("[UnityD3D11] Context release failed", ex);
}
_d3dContext = IntPtr.Zero;
}
if (_d3dDevice != IntPtr.Zero)
{
try
{
Marshal.Release(_d3dDevice);
}
catch (Exception ex2)
{
SharedTextureBridgePlugin.LogError("[UnityD3D11] Device release failed", ex2);
}
_d3dDevice = IntPtr.Zero;
}
if ((Object)(object)_probeTexture != (Object)null)
{
Object.Destroy((Object)(object)_probeTexture);
_probeTexture = null;
}
_initialized = false;
}
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.17";
}
}