using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel; using FFXIVClientStructs.FFXIV.Common.Lua; using MonoMod.Utils; using Newtonsoft.Json; using SharpDX; using SharpDX.D3DCompiler; using SharpDX.Direct3D; using SharpDX.Direct3D11; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Text.Json; using System.Threading.Tasks; using System.Xml.Linq; using TerraFX.Interop.DirectX; using SDXDevice = SharpDX.Direct3D11.Device; using XIVDevice = FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.Device; namespace CustomResolution; public unsafe class MiniShader : IDisposable { public MiniShader(string name) { Name = name; var asm = Assembly.GetExecutingAssembly(); var path = $"{nameof(CustomResolution)}.Shaders.{name}.hlsl"; using (var stream = asm.GetManifestResourceStream(path) ?? throw new FileNotFoundException(path)) using (var streamReader = new StreamReader(stream)) { Source = streamReader.ReadToEnd(); } var dev = (DeviceEx*) XIVDevice.Instance(); Ctx = CppObject.FromPointer((nint) dev->D3D11DeviceContext); Device = Ctx.Device; VS = new(Device, ShaderBytecode.Compile(Source, "vs", "vs_5_0")); PS = new(Device, ShaderBytecode.Compile(Source, "ps", "ps_5_0")); } public string Name { get; private set; } public string Source { get; private set; } public DeviceContext Ctx { get; private set; } public SDXDevice Device { get; private set; } public SharpDX.Direct3D11.VertexShader VS { get; private set; } public SharpDX.Direct3D11.PixelShader PS { get; private set; } public virtual void Dispose() { PS.Dispose(); VS.Dispose(); Device.Dispose(); } } public class MiniShaderConstants : IDisposable where T : unmanaged { private readonly MiniShader _shader; private T _value; public MiniShaderConstants(MiniShader shader) { _shader = shader; Buffer = new( _shader.Device, Math.Max(16, Marshal.SizeOf()), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, Marshal.SizeOf() ); } public SharpDX.Direct3D11.Buffer Buffer { get; private set; } public ref T Value => ref _value; public void Dispose() { Buffer.Dispose(); } public void Update() { Set(Value); } public void Set(T data) { _value = data; _shader.Ctx.UpdateSubresource(ref data, Buffer); } } public class MiniShaderState : IDisposable { private List _undos = []; public MiniShaderState() { } public void Dispose() { foreach (var undo in _undos) { undo(); } } public void Set(TOwner owner, string name, TValue value) { var prev = ReflCache.Get(owner, name); _undos.Add(() => ReflCache.Set(owner, name, prev)); ReflCache.Set(owner, name, value); } public void SetShader(CommonShaderStage stage, T? shader) where T : DeviceChild { var prev = stage.Get(); _undos.Add(() => stage.Set(prev)); stage.Set(shader!); } public void SetConstantBuffer(CommonShaderStage stage, int slot, SharpDX.Direct3D11.Buffer buffer) where T : DeviceChild { var prev = stage.GetConstantBuffers(slot, 1); _undos.Add(() => stage.SetConstantBuffer(slot, prev[0])); stage.SetConstantBuffer(slot, buffer); } public void SetShaderResource(CommonShaderStage stage, int slot, ShaderResourceView srv) where T : DeviceChild { var prev = stage.GetShaderResources(slot, 1); _undos.Add(() => stage.SetShaderResource(slot, prev[0])); stage.SetShaderResource(slot, srv); } private static class ReflCache { private static readonly Type _tOwner = typeof(TOwner); private static readonly Dictionary _props = []; private static PropertyInfo? GetProperty(string name) { if (_props.TryGetValue(name, out var prop)) { return prop; } return _props[name] = _tOwner.GetProperty(name); } public static TValue Get(TOwner owner, string name) { if (GetProperty(name) is { } prop) { return (TValue) prop.GetValue(owner)!; } return default!; } public static void Set(TOwner owner, string name, TValue value) { if (GetProperty(name) is { } prop) { prop.SetValue(owner, value); return; } } } }