From 50ad7cff36f61ac8bc672a583490b2f5433feebe Mon Sep 17 00:00:00 2001 From: Jade Macho Date: Mon, 7 Jul 2025 23:40:33 +0200 Subject: [PATCH] game: Implement mip gen and point scaling --- CustomResolution2782/ConfigurationEnums.cs | 22 +- .../CustomResolution2782.csproj | 8 +- CustomResolution2782/DisplaySizeState.cs | 4 +- CustomResolution2782/GameSizeState.cs | 263 ++++++++++++++++-- CustomResolution2782/Plugin.cs | 1 - CustomResolution2782/Windows/ConfigWindow.cs | 11 +- CustomResolution2782/packages.lock.json | 27 -- README.md | 9 - 8 files changed, 267 insertions(+), 78 deletions(-) diff --git a/CustomResolution2782/ConfigurationEnums.cs b/CustomResolution2782/ConfigurationEnums.cs index 68b11b0..27fd782 100644 --- a/CustomResolution2782/ConfigurationEnums.cs +++ b/CustomResolution2782/ConfigurationEnums.cs @@ -117,16 +117,27 @@ public static class MinSizeModeExt public enum ResolutionScalingMode { - Fast = 0, - FSR = 1, - DLSS = 2 + Point = 0, + Linear = 1, + FSR = 2, + DLSS = 3 } public static class ResolutionScalingModeExt { + public static byte ToXIV(this ResolutionScalingMode mode) => mode switch + { + ResolutionScalingMode.Point => 0, + ResolutionScalingMode.Linear => 0, + ResolutionScalingMode.FSR => 1, + ResolutionScalingMode.DLSS => 2, + _ => 0 + }; + public static string ToHumanNameString(this ResolutionScalingMode mode) => mode switch { - ResolutionScalingMode.Fast => "Fast Pixelation", + ResolutionScalingMode.Point => "Pixelated", + ResolutionScalingMode.Linear => "Blurry", ResolutionScalingMode.FSR => "AMD FSR", ResolutionScalingMode.DLSS => "NVIDIA DLSS", _ => mode.ToString(), @@ -134,7 +145,8 @@ public static class ResolutionScalingModeExt public static string? ToHumanInfoString(this ResolutionScalingMode mode) => mode switch { - ResolutionScalingMode.Fast => "Lowest quality option which results in blurry pixelation.", + ResolutionScalingMode.Point => "Lowest quality option which results in pixelation.", + ResolutionScalingMode.Linear => "Low quality option which results in blur.", ResolutionScalingMode.FSR => "Upscaling which works on any GPU for low performance overhead.", ResolutionScalingMode.DLSS => "DLSS in FFXIV is buggy, even without any plugins.", _ => null diff --git a/CustomResolution2782/CustomResolution2782.csproj b/CustomResolution2782/CustomResolution2782.csproj index d3de3a4..0abb272 100644 --- a/CustomResolution2782/CustomResolution2782.csproj +++ b/CustomResolution2782/CustomResolution2782.csproj @@ -19,6 +19,7 @@ false true CustomResolution + true @@ -30,7 +31,6 @@ - $(DalamudLibPath)FFXIVClientStructs.dll false @@ -71,9 +71,11 @@ $(DalamudLibPath)SharpDX.Mathematics.dll false - + + $(DalamudLibPath)TerraFX.Interop.Windows.dll + false + - diff --git a/CustomResolution2782/DisplaySizeState.cs b/CustomResolution2782/DisplaySizeState.cs index a16a048..e1bd7d5 100644 --- a/CustomResolution2782/DisplaySizeState.cs +++ b/CustomResolution2782/DisplaySizeState.cs @@ -6,6 +6,7 @@ using FloppyUtils; using System; using System.Runtime.InteropServices; using System.Text; +using TerraFX.Interop.DirectX; using TerraFX.Interop.Windows; using static TerraFX.Interop.Windows.Windows; @@ -421,13 +422,14 @@ public unsafe struct DeviceEx public ref uint NewHeight => ref _.NewHeight; // C# doesn't let us use ptr types as generic arguments, oh well. + public readonly ID3D11DeviceContext* D3D11DeviceContext => (ID3D11DeviceContext*) _.D3D11DeviceContext; public readonly ImmediateContextEx* ImmediateContext => (ImmediateContextEx*) _.ImmediateContext; } // ImmediateContextEx in FFXIVClientStructs is a bare minimum. // https://github.com/aers/FFXIVClientStructs/blob/ef5e9a5997671fb2c9a72cb9d57d841855f62085/FFXIVClientStructs/FFXIV/Client/Graphics/Kernel/ImmediateContext.cs [StructLayout(LayoutKind.Explicit)] -public struct ImmediateContextEx +public unsafe struct ImmediateContextEx { [FieldOffset(0)] public ImmediateContext _; diff --git a/CustomResolution2782/GameSizeState.cs b/CustomResolution2782/GameSizeState.cs index 04afe9c..3218682 100644 --- a/CustomResolution2782/GameSizeState.cs +++ b/CustomResolution2782/GameSizeState.cs @@ -4,10 +4,13 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel; using FFXIVClientStructs.FFXIV.Client.Graphics.Render; using FFXIVClientStructs.FFXIV.Client.System.Framework; using FloppyUtils; +using SharpDX; using System; using System.Runtime.InteropServices; using System.Text; -using TerraFX.Interop.Windows; +using TerraFX.Interop.DirectX; +using Device = FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.Device; +using SDX11 = SharpDX.Direct3D11; namespace CustomResolution; @@ -17,17 +20,44 @@ public unsafe class GameSizeState : IDisposable private Hook _rtmApplyScalingHook; private Hook _rtmDestroyAfterResizeHook; private Hook _rtmRegenAfterResizeHook; - private Hook _icdx11ProcessCommandsHook; + private Hook _immediateProcessCommandsHook; private Hook _ddx11PostTickHook; private Hook _taskRenderGraphicsRenderHook; + private Hook _prepareTextureHook; + private Hook _immediateBindPSSRVsHook; + private Hook _immediateBindCSSRVsHook; + private Hook _createTexture2DHook; + + private SDX11.DeviceContext _d3dctx; + private SDX11.Device _d3ddev; + private SDX11.SamplerState _samplerMips; + private SDX11.SamplerState _samplerPoint; private bool _wasEnabled = false; private object _renderLock = new(); private ForceUpdateRTMState _forceUpdateRTM = ForceUpdateRTMState._0_Idle; + private uint _drawCount; + public GameSizeState() { + var dev = (DeviceEx*) Device.Instance(); + _d3dctx = CppObject.FromPointer((nint) dev->D3D11DeviceContext); + _d3ddev = _d3dctx.Device; + + var samplerDesc = SDX11.SamplerStateDescription.Default(); + samplerDesc.Filter = SDX11.Filter.MinMagMipLinear; + samplerDesc.AddressU = SDX11.TextureAddressMode.Mirror; + samplerDesc.AddressV = SDX11.TextureAddressMode.Mirror; + samplerDesc.AddressW = SDX11.TextureAddressMode.Mirror; + _samplerMips = new(_d3ddev, samplerDesc); + + samplerDesc.Filter = SDX11.Filter.MinMagMipPoint; + samplerDesc.MinimumLod = 0; + samplerDesc.MaximumLod = 0; + _samplerPoint = new(_d3ddev, samplerDesc); + /* Writes DynamicResolutionTargetHeight to size[1] near the end, * but if in (gpose || main menu), only scale < 1?? */ @@ -37,8 +67,6 @@ public unsafe class GameSizeState : IDisposable ); _rtmApplyScalingHook.Enable(); - var dev = (DeviceEx*) Device.Instance(); - /* Device.RequestResolutionChange and other triggers run some callbacks, namely * (at the time of 7.2) 0x40 for RTM destruction and 0x48 for RTM reconstruction, * registered in RTM init and run in PostTick. @@ -70,11 +98,11 @@ public unsafe class GameSizeState : IDisposable * with some other race conditions regarding the fields we modify. * Let's wrap it in a C# lock and call it a day... */ - _icdx11ProcessCommandsHook = Service.GameInteropProvider.HookFromAddress( + _immediateProcessCommandsHook = Service.GameInteropProvider.HookFromAddress( Service.SigScanner.ScanText("48 89 5C 24 10 48 89 6C 24 18 56 57 41 56 48 83 EC 30 48 8B 01 41 8B F0 48 8B EA"), - ICDX11ProcessCommandsDetour + ImmediateProcessCommandsDetour ); - _icdx11ProcessCommandsHook.Enable(); + _immediateProcessCommandsHook.Enable(); _ddx11PostTickHook = Service.GameInteropProvider.HookFromAddress( Service.SigScanner.ScanText("48 89 5C 24 10 48 89 6C 24 18 48 89 74 24 20 57 41 54 41 55 41 56 41 57 B8 30 43 00 00 ?? ?? ?? ?? ?? 48 2B E0 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? 00 00 8B 15"), @@ -100,6 +128,38 @@ public unsafe class GameSizeState : IDisposable TaskRenderGraphicsRenderDetour ); _taskRenderGraphicsRenderHook.Enable(); + + /* Texture preparation used in a lot of places, but most notable for + * writing to the mip level count of the gameplay texture and also updating the D3D11 ptrs. + */ + _prepareTextureHook = Service.GameInteropProvider.HookFromAddress( + Service.SigScanner.ScanText("40 53 48 83 EC 20 48 8B 02 48 8B D9 48 89 41 38 48 8B 02 48 89 41 40"), + PrepareTextureDetour + ); + _prepareTextureHook.Enable(); + + /* The shader resource view of GameplayTexture gets read by these two. + */ + _immediateBindPSSRVsHook = Service.GameInteropProvider.HookFromAddress( + Service.SigScanner.ScanText("48 8B C4 4C 89 40 18 48 89 48 08 53 56 48 83 EC 68 44 8B 5A 44 48 8D B1 E8 03 00 00 4C 89 68 D8"), + ImmediateBindPSSRVsDetour + ); + _immediateBindPSSRVsHook.Enable(); + _immediateBindCSSRVsHook = Service.GameInteropProvider.HookFromAddress( + Service.SigScanner.ScanText("48 8B C4 4C 89 40 18 48 89 48 08 53 56 48 83 EC 68 44 8B 5A 44 48 8D B1 E8 13 00 00 4C 89 68 D8"), + ImmediateBindCSSRVsDetour + ); + _immediateBindCSSRVsHook.Enable(); + + /* And because all that isn't bad enough: + * Hook ID3D11Device funcs based on their vtable indices, to allow mipmap generation, + * and to allow changing the sampler state before drawing. + */ + _createTexture2DHook = Service.GameInteropProvider.HookFromAddress( + ((ID3D11Device*) _d3ddev.NativePointer)->lpVtbl[5], + CreateTexture2DDetour + ); + _createTexture2DHook.Enable(); } public bool ConfigDynRezo { get; private set; } @@ -121,7 +181,7 @@ public unsafe class GameSizeState : IDisposable private delegate void RTMRegenAfterResize(); // [UnmanagedFunctionPointer(CallingConvention.FastCall)] - private delegate void ICDX11ProcessCommands(ImmediateContext* ctx, RenderCommandBufferGroup* cmds, uint count); + private delegate void ImmediateProcessCommands(ImmediateContext* ctx, RenderCommandBufferGroup* cmds, uint count); // [UnmanagedFunctionPointer(CallingConvention.FastCall)] private delegate void DDX11PostTick(DeviceEx* dev); @@ -129,14 +189,37 @@ public unsafe class GameSizeState : IDisposable // [UnmanagedFunctionPointer(CallingConvention.FastCall)] private delegate void TaskRenderGraphicsRender(); + // [UnmanagedFunctionPointer(CallingConvention.FastCall)] + private delegate ulong PrepareTexture(Texture* tex, uint* size, byte mips, uint format); + + // [UnmanagedFunctionPointer(CallingConvention.FastCall)] + private delegate void ImmediateBindPSSRVs(ImmediateContextEx* im, PixelShader* ps, ImmediateSRV* data); + + // [UnmanagedFunctionPointer(CallingConvention.FastCall)] + private delegate void ImmediateBindCSSRVs(ImmediateContextEx* im, Shader* cs, ImmediateSRV* data); + + private delegate int CreateTexture2D(ID3D11Device* d3ddev, D3D11_TEXTURE2D_DESC* desc, D3D11_SUBRESOURCE_DATA* initialData, ID3D11Texture2D** tex); + + private delegate void Draw(ID3D11DeviceContext* d3dctx, uint vertexCount, uint startVertexLocation); + public void Dispose() { _rtmApplyScalingHook.Dispose(); _rtmDestroyAfterResizeHook.Dispose(); _rtmRegenAfterResizeHook.Dispose(); - _icdx11ProcessCommandsHook.Dispose(); + _immediateProcessCommandsHook.Dispose(); _ddx11PostTickHook.Dispose(); _taskRenderGraphicsRenderHook.Dispose(); + _prepareTextureHook.Dispose(); + _immediateBindPSSRVsHook.Dispose(); + _immediateBindCSSRVsHook.Dispose(); + _createTexture2DHook.Dispose(); + lock (_renderLock) + { + _samplerPoint.Dispose(); + _samplerMips.Dispose(); + } + _d3ddev.Dispose(); Service.Framework.RunOnFrameworkThread(Update); } @@ -157,10 +240,7 @@ public unsafe class GameSizeState : IDisposable if (Service.DebugConfig.IsDebug) { - _dbg.Append(@$"RTMApplyScaling 0x{(_rtmApplyScalingHook.IsDisposed ? null : _rtmApplyScalingHook.Address):X16} -RTMRegenAfterResize 0x{(_rtmRegenAfterResizeHook.IsDisposed ? null : _rtmRegenAfterResizeHook.Address):X16} -ICDX11ProcessCommands 0x{(_icdx11ProcessCommandsHook.IsDisposed ? null : _icdx11ProcessCommandsHook.Address):X16} -DR !{gfx->DynamicRezoEnable} +{gfx->DynamicRezoEnableBeyond1} _{gfx->DynamicRezoEnableCutScene} ?{gfx->DynamicRezoEnableUnkx47} ?{gfx->DynamicRezoEnableUnkx48} + _dbg.Append(@$"DR !{gfx->DynamicRezoEnable} +{gfx->DynamicRezoEnableBeyond1} _{gfx->DynamicRezoEnableCutScene} ?{gfx->DynamicRezoEnableUnkx47} ?{gfx->DynamicRezoEnableUnkx48} GR x{gfx->GraphicsRezoScale} ?{gfx->GraphicsRezoUnk1} _{gfx->GraphicsRezoUpscaleType} ?{gfx->GraphicsRezoUnk2} DEV 0x{(long) (nint) dev:X16} GFX 0x{(long) (nint) gfx:X16} @@ -181,7 +261,7 @@ RR {dev->RequestRender} 0x{(long) dev->ImmediateContext->IfNonZeroSkipPostTickPr gfx->DynamicRezoEnable = (byte) (ConfigDynRezo || enabled ? 1 : 0); if (enabled) { - gfx->GraphicsRezoUpscaleType = (byte) (cfg.Scale <= 1f ? Service.Config._.ResolutionScalingMode : ResolutionScalingMode.Fast); + gfx->GraphicsRezoUpscaleType = cfg.Scale <= 1f ? Service.Config._.ResolutionScalingMode.ToXIV() : ResolutionScalingMode.Linear.ToXIV(); rtm->DynamicResolutionMinimumHeight = rtm->DynamicResolutionMaximumHeight; } else @@ -194,9 +274,8 @@ RR {dev->RequestRender} 0x{(long) dev->ImmediateContext->IfNonZeroSkipPostTickPr var scale = MathF.Max(1f, enabled ? cfg.Scale : 1f); GetScaledWidthHeight(dev->Width, dev->Height, scale, out var widthS, out var heightS); - // TODO: Figure out a more consistent way to get to the currently allocated size. // Check if the backing RTs are the expected size. - var tex = rtm->_.Unk20[0].Value; + var tex = rtm->GameplayTextureUnk1; if (tex->AllocatedWidth != widthS || tex->AllocatedHeight != heightS) { if (!unloading) @@ -274,7 +353,7 @@ RR {dev->RequestRender} 0x{(long) dev->ImmediateContext->IfNonZeroSkipPostTickPr var gfx = (GraphicsConfigEx*) GraphicsConfig.Instance(); var _DynamicRezoEnableBeyond1 = gfx->DynamicRezoEnableBeyond1; - gfx->DynamicRezoEnableBeyond1 = 1; + gfx->DynamicRezoEnableBeyond1 = (byte) (cfg.Scale > 1f ? 1 : 0); Service.PluginLog.Debug($"Applying scaling, before: {size[0]} {size[1]} {unk1}"); _rtmApplyScalingHook.OriginalDisposeSafe(rtm, size, unk1); @@ -295,7 +374,7 @@ RR {dev->RequestRender} 0x{(long) dev->ImmediateContext->IfNonZeroSkipPostTickPr Service.PluginLog.Debug($"Destroying RTM resources"); byte rv = _rtmDestroyAfterResizeHook.OriginalDisposeSafe(); - Service.PluginLog.Debug($"After: 0x{(long) (nint) rtm->_.Unk20[0].Value->D3D11Texture2D:X16}"); + Service.PluginLog.Debug($"After: {rv} 0x{(long) (nint) rtm->GameplayTextureUnk1->D3D11Texture2D:X16} 0x{(long) (nint) rtm->GameplayTextureUnk3->D3D11Texture2D:X16}"); return rv; } @@ -314,14 +393,17 @@ RR {dev->RequestRender} 0x{(long) dev->ImmediateContext->IfNonZeroSkipPostTickPr using var scale = new ScaleState(); Service.PluginLog.Debug($"Regenerating RTM resources: {dev->Width} x {dev->Height}"); _rtmRegenAfterResizeHook.OriginalDisposeSafe(); - Service.PluginLog.Debug($"After: 0x{(long) (nint) rtm->_.Unk20[0].Value->D3D11Texture2D:X16}"); + Service.PluginLog.Debug($"After: 0x{(long) (nint) rtm->GameplayTextureUnk1->D3D11Texture2D:X16} 0x{(long) (nint) rtm->GameplayTextureUnk3->D3D11Texture2D:X16}"); } - private void ICDX11ProcessCommandsDetour(ImmediateContext* ctx, RenderCommandBufferGroup* cmds, uint count) + private void ImmediateProcessCommandsDetour(ImmediateContext* ctx, RenderCommandBufferGroup* cmds, uint count) { + _drawCount = 0; + // Service.PluginLog.Debug("--- ImmediateProcessCommands ---"); + lock (_renderLock) { - _icdx11ProcessCommandsHook.OriginalDisposeSafe(ctx, cmds, count); + _immediateProcessCommandsHook.OriginalDisposeSafe(ctx, cmds, count); } } @@ -346,6 +428,112 @@ RR {dev->RequestRender} 0x{(long) dev->ImmediateContext->IfNonZeroSkipPostTickPr } } + private ulong PrepareTextureDetour(Texture* tex, uint* size, byte mips, uint format) + { + var rtm = (RenderTargetManagerEx*) RenderTargetManager.Instance(); + if (tex != rtm->GameplayTextureUnk1 && tex != rtm->GameplayTextureUnk3) + { + return _prepareTextureHook.OriginalDisposeSafe(tex, size, mips, format); + } + + ref var cfg = ref Service.Config._; + + if (!Service.Plugin.Unloading && cfg.Game.IsEnabled && cfg.Game.Scale > 2f) + { + mips = (byte) MathF.Ceiling(MathF.Log2(cfg.Game.Scale)); + } + + Service.PluginLog.Debug($"Preparing gameplay texture 0x{(long) (nint) tex:X16} with {mips} mips, currently 0x{(long) (nint) tex->D3D11Texture2D:X16}"); + var rv = _prepareTextureHook.OriginalDisposeSafe(tex, size, mips, format); + Service.PluginLog.Debug($"After: 0x{rv:X16} 0x{(long) (nint) tex->D3D11Texture2D:X16} 0x{(long) (nint) tex->D3D11ShaderResourceView:X16}"); + return rv; + } + + private void ImmediateBindPSCSSRVsDetourCommon( + bool isPS, + SDX11.CommonShaderStage stage, + ImmediateContextEx* im, PixelShader* ps, ImmediateSRV* data + ) + { + var rtm = (RenderTargetManagerEx*) RenderTargetManager.Instance(); + bool called = false; + + // TODO: Identifying by the shader might be much more reliable long-term. + if (ps->Shader.SamplerCount >= 1 && (data[0].Texture == rtm->GameplayTextureUnk1 || data[0].Texture == rtm->GameplayTextureUnk3)) + { + // Service.PluginLog.Debug($"ImmediateBind{(isPS ? "PS" : "CS")}SRVs #{_drawCount} 0x{(long) (nint) ps}"); + var tex = data[0].Texture; + + Orig(); + + if (Service.Config._.Game.IsEnabled && Service.Config._.ResolutionScalingMode == ResolutionScalingMode.Point) + { + stage.SetSampler(0, _samplerPoint); + if (!isPS) + { + _d3dctx.PixelShader.SetSampler(0, _samplerPoint); + } + } + else if (tex->MipLevel != 1) + { + _d3dctx.PixelShader.SetSampler(0, _samplerMips); + if (!isPS) + { + _d3dctx.PixelShader.SetSampler(0, _samplerMips); + } + _d3dctx.GenerateMips(CppObject.FromPointer((nint) tex->D3D11ShaderResourceView)); + } + } + + Orig(); + + void Orig() + { + if (called) + { + return; + } + + called = true; + _drawCount++; + + if (isPS) + { + _immediateBindPSSRVsHook.OriginalDisposeSafe(im, ps, data); + } + else + { + _immediateBindCSSRVsHook.OriginalDisposeSafe(im, (Shader*) ps, data); + } + } + } + + private void ImmediateBindPSSRVsDetour(ImmediateContextEx* im, PixelShader* ps, ImmediateSRV* data) + { + ImmediateBindPSCSSRVsDetourCommon(true, _d3dctx.PixelShader, im, ps, data); + } + + private void ImmediateBindCSSRVsDetour(ImmediateContextEx* im, Shader* cs, ImmediateSRV* data) + { + ImmediateBindPSCSSRVsDetourCommon(false, _d3dctx.ComputeShader, im, (PixelShader*) cs, data); + } + + private int CreateTexture2DDetour(ID3D11Device* d3ddev, D3D11_TEXTURE2D_DESC* desc, D3D11_SUBRESOURCE_DATA* initialData, ID3D11Texture2D** tex) + { + var rtm = (RenderTargetManagerEx*) RenderTargetManager.Instance(); + if (tex != &rtm->GameplayTextureUnk1->D3D11Texture2D && tex != &rtm->GameplayTextureUnk3->D3D11Texture2D) + { + return _createTexture2DHook.OriginalDisposeSafe(d3ddev, desc, initialData, tex); + } + + if (rtm->GameplayTextureUnk1->MipLevel != 1) + { + desc->MiscFlags |= (uint) D3D11_RESOURCE_MISC_FLAG.D3D11_RESOURCE_MISC_GENERATE_MIPS; + } + + return _createTexture2DHook.OriginalDisposeSafe(d3ddev, desc, initialData, tex); + } + private enum ForceUpdateRTMState { _0_Idle, @@ -384,7 +572,6 @@ public unsafe struct GraphicsConfigEx [FieldOffset(0)] public GraphicsConfig _; -// CRES_CLEAN never public ref byte DynamicRezoEnable => ref _.DynamicRezoEnable; // Set to 0 in main menu and gpose, preventing scaling beyond 1. public ref byte DynamicRezoEnableBeyond1 => ref RefPtr.For(ref DynamicRezoEnable).Offs(0x1).Ref; @@ -406,6 +593,20 @@ public unsafe struct RenderTargetManagerEx [FieldOffset(0)] public RenderTargetManager _; + // Totle screen: Gets blitted FROM after actual gameplay texture. Actual purpose unknown. + // Im-game outdoors: Gets blitted to backbuffer. + [FieldOffset(0x68)] + public Texture* GameplayTextureUnk1; + + // Gets blitted TO after actual gameplay texture, using Unk1. Actual purpose unknown. + [FieldOffset(0x100)] + public Texture* GameplayTextureUnk2; + + // Title screen: Gets blitted to backbuffer. + // In-game outdoors: Totally unknown. + [FieldOffset(0x258)] + public Texture* GameplayTextureUnk3; + [FieldOffset(0x428)] public uint Resolution_Width; [FieldOffset(0x428 + 0x4)] @@ -431,3 +632,21 @@ public unsafe struct RenderTargetManagerEx [FieldOffset(0x70C + 4 * 4)] public float GraphicsRezoScaleUnk2; } + +[StructLayout(LayoutKind.Explicit, Size = 0x18)] +public unsafe struct ImmediateSRV +{ + // D3D11ShaderResourceView must be at 0x58 + (GlobalIndex % 3) * 8 + // Smells like something swapchain-adjacent, but have yet to analyze anything with != null. + [FieldOffset(0x0)] + public nint Unkx0; + + [FieldOffset(0x8)] + public Texture* Texture; + + [FieldOffset(0x10)] + public uint Unkx10; + + [FieldOffset(0x14)] + public uint Unkx14; +} diff --git a/CustomResolution2782/Plugin.cs b/CustomResolution2782/Plugin.cs index 62893ca..22e0ee8 100644 --- a/CustomResolution2782/Plugin.cs +++ b/CustomResolution2782/Plugin.cs @@ -2,7 +2,6 @@ using Dalamud.Game.Config; using Dalamud.Plugin; using Dalamud.Plugin.Services; -using FFXIVClientStructs.FFXIV.Client.System.Framework; using ImGuiNET; using System; using System.Collections.Generic; diff --git a/CustomResolution2782/Windows/ConfigWindow.cs b/CustomResolution2782/Windows/ConfigWindow.cs index ab251ac..a249a0a 100644 --- a/CustomResolution2782/Windows/ConfigWindow.cs +++ b/CustomResolution2782/Windows/ConfigWindow.cs @@ -154,16 +154,7 @@ Changed via /gres"); DrawSizeTabShared(ref _.Game, "Game", scaleOnly: true); - using (_.Game.Scale > 2f ? ImRaii.PushColor(ImGuiCol.Border, 0xff00ffff) : null) - { - ImGui.InputFloat("Scale", ref _.Game.Scale, 0.01f, 0.1f, "%.3f", ImGuiInputTextFlags.None); - } - - if (_.Game.Scale > 2f && ImGui.IsItemHovered()) - { - ImGui.SetTooltip(@"Scaling larger than 2x currently doesn't improve antialiasing! -This is still being worked on before the v1.0 release."); - } + ImGui.InputFloat("Scale", ref _.Game.Scale, 0.01f, 0.1f, "%.3f", ImGuiInputTextFlags.None); if (ImGui.BeginCombo("Graphics Upscaling", _.ResolutionScalingMode.ToHumanNameString())) { diff --git a/CustomResolution2782/packages.lock.json b/CustomResolution2782/packages.lock.json index 6b40e5f..57051b7 100644 --- a/CustomResolution2782/packages.lock.json +++ b/CustomResolution2782/packages.lock.json @@ -8,27 +8,6 @@ "resolved": "12.0.0", "contentHash": "J5TJLV3f16T/E2H2P17ClWjtfEBPpq3yxvqW46eN36JCm6wR+EaoaYkqG9Rm5sHqs3/nK/vKjWWyvEs/jhKoXw==" }, - "SharpDX.D3DCompiler": { - "type": "Direct", - "requested": "[4.2.0, )", - "resolved": "4.2.0", - "contentHash": "Rnsd6Ilp127xbXqhTit8WKFQUrXwWxqVGpglyWDNkIBCk0tWXNQEjrJpsl0KAObzyZaa33+EXAikLVt5fnd3GA==", - "dependencies": { - "NETStandard.Library": "1.6.1", - "SharpDX": "4.2.0" - } - }, - "SharpDX.Direct2D1": { - "type": "Direct", - "requested": "[4.2.0, )", - "resolved": "4.2.0", - "contentHash": "Qs8LzDMaQf1u3KB8ArHu9pDv6itZ++QXs99a/bVAG+nKr0Hx5NG4mcN5vsfE0mVR2TkeHfeUm4PksRah6VUPtA==", - "dependencies": { - "NETStandard.Library": "1.6.1", - "SharpDX": "4.2.0", - "SharpDX.DXGI": "4.2.0" - } - }, "SharpDX.Direct3D11": { "type": "Direct", "requested": "[4.2.0, )", @@ -40,12 +19,6 @@ "SharpDX.DXGI": "4.2.0" } }, - "TerraFX.Interop.Windows": { - "type": "Direct", - "requested": "[10.0.22621.2, )", - "resolved": "10.0.22621.2", - "contentHash": "lORoYCoURS33Vi7PDvubRugLF2+l5v3rX2oVEqNhpBLjs3aZpqapRvTHPKVwsC+dGrsGuqJ/3yXuxVUb0vl3vg==" - }, "Microsoft.NETCore.Platforms": { "type": "Transitive", "resolved": "1.1.0", diff --git a/README.md b/README.md index a723a3f..d0be9e4 100644 --- a/README.md +++ b/README.md @@ -23,15 +23,6 @@ everything where it was while still allowing you to switch between game scaling is that this does NOT affect the screenshot resolution. -
I'm scaling by 3x or higher, but I'm still getting jagged edges! -The plugin currently only gives FFXIV a fake resolution to work with internally, but it doesn't ensure that the -extra pixels land on your screen. When scaling the display resolution, those will still be used for in-game or ReShade screenshots though. - -Windows should perform basic filtering with 2x scaling (it might not work on some graphics cards?), and I haven't -heard back from anyone using this on Linux yet. But an universal fix for this is possible - it just requires more -time than I have on my hands right now. -
-
I'm using DLSS, and my game looks pixelated / is small! DLSS in FFXIV is bugged. No, I'm not joking: even without any plugins or mods loaded, it can glitch out when simply resizing the window (most notably by rapidly pressing WinKey + Down and WinKey + Up).