184 lines
4.9 KiB
C#
184 lines
4.9 KiB
C#
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<DeviceContext>((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<T> : 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<T>()),
|
|
ResourceUsage.Default,
|
|
BindFlags.ConstantBuffer,
|
|
CpuAccessFlags.None,
|
|
ResourceOptionFlags.None,
|
|
Marshal.SizeOf<T>()
|
|
);
|
|
}
|
|
|
|
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<Action> _undos = [];
|
|
|
|
public MiniShaderState()
|
|
{
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
foreach (var undo in _undos)
|
|
{
|
|
undo();
|
|
}
|
|
}
|
|
|
|
public void Set<TOwner, TValue>(TOwner owner, string name, TValue value)
|
|
{
|
|
var prev = ReflCache<TOwner>.Get<TValue>(owner, name);
|
|
_undos.Add(() => ReflCache<TOwner>.Set(owner, name, prev));
|
|
ReflCache<TOwner>.Set(owner, name, value);
|
|
}
|
|
|
|
public void SetShader<T>(CommonShaderStage<T> stage, T? shader) where T : DeviceChild
|
|
{
|
|
var prev = stage.Get();
|
|
_undos.Add(() => stage.Set(prev));
|
|
stage.Set(shader!);
|
|
}
|
|
|
|
public void SetConstantBuffer<T>(CommonShaderStage<T> 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<T>(CommonShaderStage<T> 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<TOwner>
|
|
{
|
|
private static readonly Type _tOwner = typeof(TOwner);
|
|
private static readonly Dictionary<string, PropertyInfo?> _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<TValue>(TOwner owner, string name)
|
|
{
|
|
if (GetProperty(name) is { } prop)
|
|
{
|
|
return (TValue) prop.GetValue(owner)!;
|
|
}
|
|
|
|
return default!;
|
|
}
|
|
|
|
public static void Set<TValue>(TOwner owner, string name, TValue value)
|
|
{
|
|
if (GetProperty(name) is { } prop)
|
|
{
|
|
prop.SetValue(owner, value);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|