mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
dxgi_testing
This commit is contained in:
parent
45f3e17acb
commit
b5bb5a0077
10 changed files with 592 additions and 3 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "lib/ImGui.NET"]
|
||||||
|
path = lib/ImGui.NET
|
||||||
|
url = https://github.com/ff-meli/ImGui.NET.git
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
<DocumentationFile></DocumentationFile>
|
<DocumentationFile></DocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="EasyHook" Version="2.7.7097" />
|
<PackageReference Include="EasyHook" Version="2.7.6270" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Dalamud.DiscordBot;
|
using Dalamud.DiscordBot;
|
||||||
using Dalamud.Game.Chat;
|
using Dalamud.Game.Chat;
|
||||||
|
|
@ -34,6 +35,7 @@ namespace Dalamud.Injector {
|
||||||
process = Process.Start(
|
process = Process.Start(
|
||||||
"C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\ffxiv_dx11.exe",
|
"C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\ffxiv_dx11.exe",
|
||||||
"DEV.TestSID=0 DEV.UseSqPack=1 DEV.DataPathType=1 DEV.LobbyHost01=127.0.0.1 DEV.LobbyPort01=54994 DEV.LobbyHost02=127.0.0.1 DEV.LobbyPort02=54994 DEV.LobbyHost03=127.0.0.1 DEV.LobbyPort03=54994 DEV.LobbyHost04=127.0.0.1 DEV.LobbyPort04=54994 DEV.LobbyHost05=127.0.0.1 DEV.LobbyPort05=54994 DEV.LobbyHost06=127.0.0.1 DEV.LobbyPort06=54994 DEV.LobbyHost07=127.0.0.1 DEV.LobbyPort07=54994 DEV.LobbyHost08=127.0.0.1 DEV.LobbyPort08=54994 SYS.Region=0 language=1 version=1.0.0.0 DEV.MaxEntitledExpansionID=2 DEV.GMServerHost=127.0.0.1 DEV.GameQuitMessageBox=0");
|
"DEV.TestSID=0 DEV.UseSqPack=1 DEV.DataPathType=1 DEV.LobbyHost01=127.0.0.1 DEV.LobbyPort01=54994 DEV.LobbyHost02=127.0.0.1 DEV.LobbyPort02=54994 DEV.LobbyHost03=127.0.0.1 DEV.LobbyPort03=54994 DEV.LobbyHost04=127.0.0.1 DEV.LobbyPort04=54994 DEV.LobbyHost05=127.0.0.1 DEV.LobbyPort05=54994 DEV.LobbyHost06=127.0.0.1 DEV.LobbyPort06=54994 DEV.LobbyHost07=127.0.0.1 DEV.LobbyPort07=54994 DEV.LobbyHost08=127.0.0.1 DEV.LobbyPort08=54994 SYS.Region=0 language=1 version=1.0.0.0 DEV.MaxEntitledExpansionID=2 DEV.GMServerHost=127.0.0.1 DEV.GameQuitMessageBox=0");
|
||||||
|
Thread.Sleep(10000);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
process = Process.GetProcessById(pid);
|
process = Process.GetProcessById(pid);
|
||||||
|
|
|
||||||
10
Dalamud.sln
10
Dalamud.sln
|
|
@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud", "Dalamud\Dalamud.
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud.Injector", "Dalamud.Injector\Dalamud.Injector.csproj", "{5B832F73-5F54-4ADC-870F-D0095EF72C9A}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dalamud.Injector", "Dalamud.Injector\Dalamud.Injector.csproj", "{5B832F73-5F54-4ADC-870F-D0095EF72C9A}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImGui.NET-472", "lib\ImGui.NET\src\ImGui.NET-472\ImGui.NET-472.csproj", "{0483026E-C6CE-4B1A-AA68-46544C08140B}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -31,6 +33,14 @@ Global
|
||||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|Any CPU.Build.0 = Release|Any CPU
|
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x64.ActiveCfg = Release|x64
|
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x64.ActiveCfg = Release|x64
|
||||||
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x64.Build.0 = Release|x64
|
{5B832F73-5F54-4ADC-870F-D0095EF72C9A}.Release|x64.Build.0 = Release|x64
|
||||||
|
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{0483026E-C6CE-4B1A-AA68-46544C08140B}.Release|x64.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,9 @@ using Dalamud.Game.ClientState.Actors.Types;
|
||||||
using Dalamud.Game.ClientState.Actors.Types.NonPlayer;
|
using Dalamud.Game.ClientState.Actors.Types.NonPlayer;
|
||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
using Dalamud.Game.Internal;
|
using Dalamud.Game.Internal;
|
||||||
|
using Dalamud.Game.Internal.DXGI;
|
||||||
using Dalamud.Game.Internal.Gui;
|
using Dalamud.Game.Internal.Gui;
|
||||||
|
using Dalamud.Game.Internal.Network;
|
||||||
using Dalamud.Game.Network;
|
using Dalamud.Game.Network;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
@ -49,6 +51,8 @@ namespace Dalamud {
|
||||||
|
|
||||||
internal readonly WinSockHandlers WinSock2;
|
internal readonly WinSockHandlers WinSock2;
|
||||||
|
|
||||||
|
internal readonly SwapChain deviceHandler;
|
||||||
|
|
||||||
public Dalamud(DalamudStartInfo info) {
|
public Dalamud(DalamudStartInfo info) {
|
||||||
this.StartInfo = info;
|
this.StartInfo = info;
|
||||||
this.Configuration = DalamudConfiguration.Load(info.ConfigurationPath);
|
this.Configuration = DalamudConfiguration.Load(info.ConfigurationPath);
|
||||||
|
|
@ -81,6 +85,8 @@ namespace Dalamud {
|
||||||
|
|
||||||
this.WinSock2 = new WinSockHandlers();
|
this.WinSock2 = new WinSockHandlers();
|
||||||
|
|
||||||
|
this.deviceHandler = new SwapChain(this, this.sigScanner);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.PluginManager.LoadPlugins();
|
this.PluginManager.LoadPlugins();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup Label="Target">
|
<PropertyGroup Label="Target">
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
<TargetFramework>net471</TargetFramework>
|
<TargetFramework>net48</TargetFramework>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
@ -41,13 +41,19 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Discord.Net" Version="2.1.0" />
|
<PackageReference Include="Discord.Net" Version="2.1.0" />
|
||||||
<PackageReference Include="EasyHook" Version="2.7.7097" />
|
<PackageReference Include="EasyHook" Version="2.7.6270" />
|
||||||
<PackageReference Include="Google.Cloud.Translation.V2" Version="1.1.0" />
|
<PackageReference Include="Google.Cloud.Translation.V2" Version="1.1.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||||
<PackageReference Include="PropertyChanged.Fody" Version="2.6.1" />
|
<PackageReference Include="PropertyChanged.Fody" Version="2.6.1" />
|
||||||
<PackageReference Include="Serilog" Version="2.6.0" />
|
<PackageReference Include="Serilog" Version="2.6.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.1.0" />
|
<PackageReference Include="Serilog.Sinks.Async" Version="1.1.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
|
||||||
|
<PackageReference Include="SharpDX" Version="4.2.0" />
|
||||||
|
<PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" />
|
||||||
|
<PackageReference Include="SharpDX.DXGI" Version="4.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\lib\ImGui.NET\src\ImGui.NET-472\ImGui.NET-472.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
|
|
|
||||||
450
Dalamud/Game/Internal/DXGI/ImGuiImplDx11.cs
Normal file
450
Dalamud/Game/Internal/DXGI/ImGuiImplDx11.cs
Normal file
|
|
@ -0,0 +1,450 @@
|
||||||
|
using ImGuiNET;
|
||||||
|
using SharpDX;
|
||||||
|
using SharpDX.Direct3D;
|
||||||
|
using SharpDX.Direct3D11;
|
||||||
|
using SharpDX.DXGI;
|
||||||
|
using SharpDX.Mathematics.Interop;
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Buffer = SharpDX.Direct3D11.Buffer;
|
||||||
|
using Device = SharpDX.Direct3D11.Device;
|
||||||
|
using MapFlags = SharpDX.Direct3D11.MapFlags;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.Internal.DXGI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Currently undocumented because it is a horrible mess.
|
||||||
|
/// A near-direct port of https://github.com/ocornut/imgui/blob/master/examples/imgui_impl_dx11.cpp
|
||||||
|
/// State backup was removed because ImGui does it poorly and SharpDX makes it worse; state caching should
|
||||||
|
/// be the responsibility of the main render application anyway (which for most uses of this class does not
|
||||||
|
/// exist at all)
|
||||||
|
/// </summary>
|
||||||
|
public class ImGuiImplDx11
|
||||||
|
{
|
||||||
|
private IntPtr _renderNamePtr;
|
||||||
|
private Device _device;
|
||||||
|
private DeviceContext _deviceContext;
|
||||||
|
private ShaderResourceView _fontResourceView;
|
||||||
|
private SamplerState _fontSampler;
|
||||||
|
private VertexShader _vertexShader;
|
||||||
|
private PixelShader _pixelShader;
|
||||||
|
private InputLayout _inputLayout;
|
||||||
|
private Buffer _vertexConstantBuffer;
|
||||||
|
private BlendState _blendState;
|
||||||
|
private RasterizerState _rasterizerState;
|
||||||
|
private DepthStencilState _depthStencilState;
|
||||||
|
private Buffer _vertexBuffer;
|
||||||
|
private Buffer _indexBuffer;
|
||||||
|
private int _vertexBufferSize;
|
||||||
|
private int _indexBufferSize;
|
||||||
|
private VertexBufferBinding _vertexBinding;
|
||||||
|
// so we don't make a temporary object every frame
|
||||||
|
private RawColor4 _blendColor = new RawColor4(0, 0, 0, 0);
|
||||||
|
|
||||||
|
public void SetupRenderState(ImDrawDataPtr drawData)
|
||||||
|
{
|
||||||
|
// Setup viewport
|
||||||
|
_deviceContext.Rasterizer.SetViewport(0, 0, drawData.DisplaySize.X, drawData.DisplaySize.Y);
|
||||||
|
|
||||||
|
// Setup shader and vertex buffers
|
||||||
|
_deviceContext.InputAssembler.InputLayout = _inputLayout;
|
||||||
|
_vertexBinding.Buffer = _vertexBuffer;
|
||||||
|
_deviceContext.InputAssembler.SetVertexBuffers(0, _vertexBinding);
|
||||||
|
_deviceContext.InputAssembler.SetIndexBuffer(_indexBuffer, Format.R16_UInt, 0);
|
||||||
|
_deviceContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
|
||||||
|
_deviceContext.VertexShader.Set(_vertexShader);
|
||||||
|
_deviceContext.VertexShader.SetConstantBuffer(0, _vertexConstantBuffer);
|
||||||
|
_deviceContext.PixelShader.Set(_pixelShader);
|
||||||
|
_deviceContext.PixelShader.SetSampler(0, _fontSampler);
|
||||||
|
_deviceContext.GeometryShader.Set(null);
|
||||||
|
_deviceContext.HullShader.Set(null);
|
||||||
|
_deviceContext.DomainShader.Set(null);
|
||||||
|
_deviceContext.ComputeShader.Set(null);
|
||||||
|
|
||||||
|
// Setup blend state
|
||||||
|
_deviceContext.OutputMerger.BlendState = _blendState;
|
||||||
|
_deviceContext.OutputMerger.BlendFactor = _blendColor;
|
||||||
|
_deviceContext.OutputMerger.DepthStencilState = _depthStencilState;
|
||||||
|
_deviceContext.Rasterizer.State = _rasterizerState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RenderDrawData(ImDrawDataPtr drawData)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized
|
||||||
|
if (drawData.DisplaySize.X <= 0 || drawData.DisplaySize.Y <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!drawData.Valid || drawData.CmdListsCount == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//drawData.ScaleClipRects(ImGui.GetIO().DisplayFramebufferScale);
|
||||||
|
|
||||||
|
// Create and grow vertex/index buffers if needed
|
||||||
|
if (_vertexBuffer == null || _vertexBufferSize < drawData.TotalVtxCount)
|
||||||
|
{
|
||||||
|
_vertexBuffer?.Dispose();
|
||||||
|
_vertexBufferSize = drawData.TotalVtxCount + 5000;
|
||||||
|
|
||||||
|
_vertexBuffer = new Buffer(_device, new BufferDescription
|
||||||
|
{
|
||||||
|
Usage = ResourceUsage.Dynamic,
|
||||||
|
SizeInBytes = Unsafe.SizeOf<ImDrawVert>() * _vertexBufferSize,
|
||||||
|
BindFlags = BindFlags.VertexBuffer,
|
||||||
|
CpuAccessFlags = CpuAccessFlags.Write,
|
||||||
|
OptionFlags = ResourceOptionFlags.None
|
||||||
|
});
|
||||||
|
|
||||||
|
// (Re)make this here rather than every frame
|
||||||
|
_vertexBinding = new VertexBufferBinding
|
||||||
|
{
|
||||||
|
Buffer = _vertexBuffer,
|
||||||
|
Stride = Unsafe.SizeOf<ImDrawVert>(),
|
||||||
|
Offset = 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_indexBuffer == null || _indexBufferSize < drawData.TotalIdxCount)
|
||||||
|
{
|
||||||
|
_indexBuffer?.Dispose();
|
||||||
|
_indexBufferSize = drawData.TotalIdxCount + 10000;
|
||||||
|
|
||||||
|
_indexBuffer = new Buffer(_device, new BufferDescription
|
||||||
|
{
|
||||||
|
Usage = ResourceUsage.Dynamic,
|
||||||
|
SizeInBytes = sizeof(ushort) * _indexBufferSize, // ImGui.NET doesn't provide an ImDrawIdx, but their sample uses ushort
|
||||||
|
BindFlags = BindFlags.IndexBuffer,
|
||||||
|
CpuAccessFlags = CpuAccessFlags.Write
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload vertex/index data into a single contiguous GPU buffer
|
||||||
|
int vertexOffset = 0, indexOffset = 0;
|
||||||
|
var vertexData = _deviceContext.MapSubresource(_vertexBuffer, 0, MapMode.WriteDiscard, MapFlags.None).DataPointer;
|
||||||
|
var indexData = _deviceContext.MapSubresource(_indexBuffer, 0, MapMode.WriteDiscard, MapFlags.None).DataPointer;
|
||||||
|
|
||||||
|
for (int n = 0; n < drawData.CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
var cmdList = drawData.CmdListsRange[n];
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
System.Buffer.MemoryCopy(cmdList.VtxBuffer.Data.ToPointer(),
|
||||||
|
(ImDrawVert*)vertexData + vertexOffset,
|
||||||
|
Unsafe.SizeOf<ImDrawVert>() * _vertexBufferSize,
|
||||||
|
Unsafe.SizeOf<ImDrawVert>() * cmdList.VtxBuffer.Size);
|
||||||
|
|
||||||
|
System.Buffer.MemoryCopy(cmdList.IdxBuffer.Data.ToPointer(),
|
||||||
|
(ushort*)indexData + indexOffset,
|
||||||
|
sizeof(ushort) * _indexBufferSize,
|
||||||
|
sizeof(ushort) * cmdList.IdxBuffer.Size);
|
||||||
|
|
||||||
|
vertexOffset += cmdList.VtxBuffer.Size;
|
||||||
|
indexOffset += cmdList.IdxBuffer.Size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_deviceContext.UnmapSubresource(_vertexBuffer, 0);
|
||||||
|
_deviceContext.UnmapSubresource(_indexBuffer, 0);
|
||||||
|
|
||||||
|
// Setup orthographic projection matrix into our constant buffer
|
||||||
|
// Our visible imgui space lies from drawData.DisplayPos (top left) to drawData.DisplayPos+drawData.DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||||
|
var L = drawData.DisplayPos.X;
|
||||||
|
var R = drawData.DisplayPos.X + drawData.DisplaySize.X;
|
||||||
|
var T = drawData.DisplayPos.Y;
|
||||||
|
var B = drawData.DisplayPos.Y + drawData.DisplaySize.Y;
|
||||||
|
var mvp = new float[]
|
||||||
|
{
|
||||||
|
2f/(R-L), 0, 0, 0,
|
||||||
|
0, 2f/(T-B), 0, 0,
|
||||||
|
0, 0, 0.5f, 0,
|
||||||
|
(R+L)/(L-R), (T+B)/(B-T), 0.5f, 1f
|
||||||
|
};
|
||||||
|
|
||||||
|
var constantBuffer = _deviceContext.MapSubresource(_vertexConstantBuffer, 0, MapMode.WriteDiscard, MapFlags.None).DataPointer;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (void* mvpPtr = mvp)
|
||||||
|
{
|
||||||
|
System.Buffer.MemoryCopy(mvpPtr, constantBuffer.ToPointer(), 16 * sizeof(float), 16 * sizeof(float));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_deviceContext.UnmapSubresource(_vertexConstantBuffer, 0);
|
||||||
|
|
||||||
|
// Setup desired DX state
|
||||||
|
SetupRenderState(drawData);
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||||
|
vertexOffset = 0;
|
||||||
|
indexOffset = 0;
|
||||||
|
var clipOff = drawData.DisplayPos;
|
||||||
|
for (int n = 0; n < drawData.CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
var cmdList = drawData.CmdListsRange[n];
|
||||||
|
for (int cmd = 0; cmd < cmdList.CmdBuffer.Size; cmd++)
|
||||||
|
{
|
||||||
|
var pcmd = cmdList.CmdBuffer[cmd];
|
||||||
|
if (pcmd.UserCallback != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Apply scissor/clipping rectangle
|
||||||
|
_deviceContext.Rasterizer.SetScissorRectangle((int)(pcmd.ClipRect.X - clipOff.X), (int)(pcmd.ClipRect.Y - clipOff.Y), (int)(pcmd.ClipRect.Z - clipOff.X), (int)(pcmd.ClipRect.W - clipOff.Y));
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
// TODO: might be nice to store samplers for loaded textures so that we can look them up and apply them here
|
||||||
|
// rather than just always using the font sampler
|
||||||
|
var textureSrv = ShaderResourceView.FromPointer<ShaderResourceView>(pcmd.TextureId);
|
||||||
|
_deviceContext.PixelShader.SetShaderResource(0, textureSrv);
|
||||||
|
_deviceContext.DrawIndexed((int)pcmd.ElemCount, (int)(pcmd.IdxOffset + indexOffset), (int)(pcmd.VtxOffset + vertexOffset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
indexOffset += cmdList.IdxBuffer.Size;
|
||||||
|
vertexOffset += cmdList.VtxBuffer.Size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateFontsTexture()
|
||||||
|
{
|
||||||
|
var io = ImGui.GetIO();
|
||||||
|
|
||||||
|
// Build texture atlas
|
||||||
|
io.Fonts.GetTexDataAsRGBA32(out IntPtr fontPixels, out int fontWidth, out int fontHeight, out int fontBytesPerPixel);
|
||||||
|
|
||||||
|
// Upload texture to graphics system
|
||||||
|
var texDesc = new Texture2DDescription
|
||||||
|
{
|
||||||
|
Width = fontWidth,
|
||||||
|
Height = fontHeight,
|
||||||
|
MipLevels = 1,
|
||||||
|
ArraySize = 1,
|
||||||
|
Format = Format.R8G8B8A8_UNorm,
|
||||||
|
SampleDescription = new SampleDescription(1, 0),
|
||||||
|
Usage = ResourceUsage.Immutable,
|
||||||
|
BindFlags = BindFlags.ShaderResource,
|
||||||
|
CpuAccessFlags = CpuAccessFlags.None,
|
||||||
|
OptionFlags = ResourceOptionFlags.None
|
||||||
|
};
|
||||||
|
|
||||||
|
using (var fontTexture = new Texture2D(_device, texDesc, new DataRectangle(fontPixels, fontWidth * fontBytesPerPixel)))
|
||||||
|
{
|
||||||
|
// Create texture view
|
||||||
|
_fontResourceView = new ShaderResourceView(_device, fontTexture, new ShaderResourceViewDescription
|
||||||
|
{
|
||||||
|
Format = texDesc.Format,
|
||||||
|
Dimension = ShaderResourceViewDimension.Texture2D,
|
||||||
|
Texture2D = { MipLevels = texDesc.MipLevels }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store our identifier
|
||||||
|
io.Fonts.SetTexID(_fontResourceView.NativePointer);
|
||||||
|
io.Fonts.ClearTexData();
|
||||||
|
|
||||||
|
// Create texture sampler
|
||||||
|
_fontSampler = new SamplerState(_device, new SamplerStateDescription
|
||||||
|
{
|
||||||
|
Filter = Filter.MinMagMipLinear,
|
||||||
|
AddressU = TextureAddressMode.Wrap,
|
||||||
|
AddressV = TextureAddressMode.Wrap,
|
||||||
|
AddressW = TextureAddressMode.Wrap,
|
||||||
|
MipLodBias = 0,
|
||||||
|
ComparisonFunction = Comparison.Always,
|
||||||
|
MinimumLod = 0,
|
||||||
|
MaximumLod = 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (_device == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_fontSampler != null)
|
||||||
|
{
|
||||||
|
InvalidateDeviceObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the vertex shader
|
||||||
|
byte[] shaderData;
|
||||||
|
|
||||||
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
|
using (var stream = assembly.GetManifestResourceStream("imgui-vertex.hlsl.bytes"))
|
||||||
|
{
|
||||||
|
shaderData = new byte[stream.Length];
|
||||||
|
stream.Read(shaderData, 0, shaderData.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
_vertexShader = new VertexShader(_device, shaderData);
|
||||||
|
|
||||||
|
// Create the input layout
|
||||||
|
_inputLayout = new InputLayout(_device, shaderData, new[]
|
||||||
|
{
|
||||||
|
new InputElement("POSITION", 0, Format.R32G32_Float, 0),
|
||||||
|
new InputElement("TEXCOORD", 0, Format.R32G32_Float, 0),
|
||||||
|
new InputElement("COLOR", 0, Format.R8G8B8A8_UNorm, 0)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create the constant buffer
|
||||||
|
_vertexConstantBuffer = new Buffer(_device, new BufferDescription
|
||||||
|
{
|
||||||
|
Usage = ResourceUsage.Dynamic,
|
||||||
|
BindFlags = BindFlags.ConstantBuffer,
|
||||||
|
CpuAccessFlags = CpuAccessFlags.Write,
|
||||||
|
OptionFlags = ResourceOptionFlags.None,
|
||||||
|
SizeInBytes = 16 * sizeof(float)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create the pixel shader
|
||||||
|
using (var stream = assembly.GetManifestResourceStream("imgui-frag.hlsl.bytes"))
|
||||||
|
{
|
||||||
|
shaderData = new byte[stream.Length];
|
||||||
|
stream.Read(shaderData, 0, shaderData.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
_pixelShader = new PixelShader(_device, shaderData);
|
||||||
|
|
||||||
|
// Create the blending setup
|
||||||
|
// ...of course this was setup in a way that can't be done inline
|
||||||
|
var blendStateDesc = new BlendStateDescription();
|
||||||
|
blendStateDesc.AlphaToCoverageEnable = false;
|
||||||
|
blendStateDesc.RenderTarget[0].IsBlendEnabled = true;
|
||||||
|
blendStateDesc.RenderTarget[0].SourceBlend = BlendOption.SourceAlpha;
|
||||||
|
blendStateDesc.RenderTarget[0].DestinationBlend = BlendOption.InverseSourceAlpha;
|
||||||
|
blendStateDesc.RenderTarget[0].BlendOperation = BlendOperation.Add;
|
||||||
|
blendStateDesc.RenderTarget[0].SourceAlphaBlend = BlendOption.InverseSourceAlpha;
|
||||||
|
blendStateDesc.RenderTarget[0].DestinationAlphaBlend = BlendOption.Zero;
|
||||||
|
blendStateDesc.RenderTarget[0].AlphaBlendOperation = BlendOperation.Add;
|
||||||
|
blendStateDesc.RenderTarget[0].RenderTargetWriteMask = ColorWriteMaskFlags.All;
|
||||||
|
_blendState = new BlendState(_device, blendStateDesc);
|
||||||
|
|
||||||
|
// Create the rasterizer state
|
||||||
|
_rasterizerState = new RasterizerState(_device, new RasterizerStateDescription
|
||||||
|
{
|
||||||
|
FillMode = FillMode.Solid,
|
||||||
|
CullMode = CullMode.None,
|
||||||
|
IsScissorEnabled = true,
|
||||||
|
IsDepthClipEnabled = true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create the depth-stencil State
|
||||||
|
_depthStencilState = new DepthStencilState(_device, new DepthStencilStateDescription
|
||||||
|
{
|
||||||
|
IsDepthEnabled = false,
|
||||||
|
DepthWriteMask = DepthWriteMask.All,
|
||||||
|
DepthComparison = Comparison.Always,
|
||||||
|
IsStencilEnabled = false,
|
||||||
|
FrontFace =
|
||||||
|
{
|
||||||
|
FailOperation = StencilOperation.Keep,
|
||||||
|
DepthFailOperation = StencilOperation.Keep,
|
||||||
|
PassOperation = StencilOperation.Keep,
|
||||||
|
Comparison = Comparison.Always
|
||||||
|
},
|
||||||
|
BackFace =
|
||||||
|
{
|
||||||
|
FailOperation = StencilOperation.Keep,
|
||||||
|
DepthFailOperation = StencilOperation.Keep,
|
||||||
|
PassOperation = StencilOperation.Keep,
|
||||||
|
Comparison = Comparison.Always
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
CreateFontsTexture();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InvalidateDeviceObjects()
|
||||||
|
{
|
||||||
|
if (_device == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fontSampler?.Dispose();
|
||||||
|
_fontSampler = null;
|
||||||
|
|
||||||
|
_fontResourceView?.Dispose();
|
||||||
|
_fontResourceView = null;
|
||||||
|
ImGui.GetIO().Fonts.SetTexID(IntPtr.Zero);
|
||||||
|
|
||||||
|
_indexBuffer?.Dispose();
|
||||||
|
_indexBuffer = null;
|
||||||
|
|
||||||
|
_vertexBuffer?.Dispose();
|
||||||
|
_vertexBuffer = null;
|
||||||
|
|
||||||
|
_blendState?.Dispose();
|
||||||
|
_blendState = null;
|
||||||
|
|
||||||
|
_depthStencilState?.Dispose();
|
||||||
|
_depthStencilState = null;
|
||||||
|
|
||||||
|
_rasterizerState?.Dispose();
|
||||||
|
_rasterizerState = null;
|
||||||
|
|
||||||
|
_pixelShader?.Dispose();
|
||||||
|
_pixelShader = null;
|
||||||
|
|
||||||
|
_vertexConstantBuffer?.Dispose();
|
||||||
|
_vertexConstantBuffer = null;
|
||||||
|
|
||||||
|
_inputLayout?.Dispose();
|
||||||
|
_inputLayout = null;
|
||||||
|
|
||||||
|
_vertexShader?.Dispose();
|
||||||
|
_vertexShader = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init(Device dev, DeviceContext ctx)
|
||||||
|
{
|
||||||
|
ImGui.GetIO().BackendFlags = ImGui.GetIO().BackendFlags | ImGuiBackendFlags.RendererHasVtxOffset;
|
||||||
|
|
||||||
|
// BackendRendererName is readonly (and null) in ImGui.NET for some reason, but we can hack it via its internal pointer
|
||||||
|
_renderNamePtr = Marshal.StringToHGlobalAnsi("imgui_impl_dx11_c#");
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
ImGui.GetIO().NativePtr->BackendRendererName = (byte*)_renderNamePtr.ToPointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
_device = dev;
|
||||||
|
_deviceContext = ctx;
|
||||||
|
|
||||||
|
// SharpDX also doesn't allow reference managment
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Shutdown()
|
||||||
|
{
|
||||||
|
InvalidateDeviceObjects();
|
||||||
|
|
||||||
|
// we don't own these, so no Dispose()
|
||||||
|
_device = null;
|
||||||
|
_deviceContext = null;
|
||||||
|
|
||||||
|
if (_renderNamePtr != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(_renderNamePtr);
|
||||||
|
_renderNamePtr = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NewFrame()
|
||||||
|
{
|
||||||
|
if (_fontSampler == null)
|
||||||
|
{
|
||||||
|
CreateDeviceObjects();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
91
Dalamud/Game/Internal/DXGI/SwapChain.cs
Normal file
91
Dalamud/Game/Internal/DXGI/SwapChain.cs
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Dalamud.Hooking;
|
||||||
|
using ImGuiNET;
|
||||||
|
using Serilog;
|
||||||
|
using SharpDX.Direct3D11;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.Internal.DXGI {
|
||||||
|
public sealed class SwapChain : IDisposable {
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||||
|
private delegate IntPtr PresentDelegate(IntPtr swapChain, uint a2, uint a3);
|
||||||
|
|
||||||
|
private readonly Hook<PresentDelegate> presentHook;
|
||||||
|
|
||||||
|
private SwapChainAddressResolver Address { get; }
|
||||||
|
|
||||||
|
private readonly Dalamud dalamud;
|
||||||
|
|
||||||
|
private const string deviceguid = "3d3e0379-f9de-4d58-bb6c-18d62992f1a6";
|
||||||
|
|
||||||
|
public SwapChain(Dalamud dalamud, SigScanner scanner) {
|
||||||
|
this.dalamud = dalamud;
|
||||||
|
Address = new SwapChainAddressResolver();
|
||||||
|
Address.Setup(scanner);
|
||||||
|
|
||||||
|
Log.Verbose("===== S W A P C H A I N =====");
|
||||||
|
Log.Verbose("Present address {Present}", Address.Present);
|
||||||
|
|
||||||
|
this.presentHook =
|
||||||
|
new Hook<PresentDelegate>(Address.Present,
|
||||||
|
new PresentDelegate(PresentDetour),
|
||||||
|
this);
|
||||||
|
Enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Enable() {
|
||||||
|
this.presentHook.Enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
this.presentHook.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImGuiImplDx11 impl;
|
||||||
|
|
||||||
|
private IntPtr PresentDetour(IntPtr swapChain, uint a2, uint a3) {
|
||||||
|
|
||||||
|
|
||||||
|
if (this.impl == null) {
|
||||||
|
var ret = this.presentHook.Original(swapChain, a2, a3);
|
||||||
|
|
||||||
|
Log.Debug($"CDXGISwapChain::Present: swapChain->{swapChain.ToInt64():X} a2->{a2:X} a3->{a3:X} RET=>{ret.ToInt64():X}");
|
||||||
|
|
||||||
|
var s = new SharpDX.DXGI.SwapChain(swapChain);
|
||||||
|
var d = s.GetDevice<Device>();
|
||||||
|
var ctx = d.ImmediateContext;
|
||||||
|
//s.GetDevice(Guid.Parse(deviceguid), out var device);
|
||||||
|
|
||||||
|
Log.Verbose($"DEVICE: {d.NativePointer.ToInt64():X} CONTEXT: {ctx.NativePointer.ToInt64():X}");
|
||||||
|
|
||||||
|
ImGui.CreateContext();
|
||||||
|
ImGui.StyleColorsDark();
|
||||||
|
|
||||||
|
this.impl = new ImGuiImplDx11();
|
||||||
|
this.impl.Init(d, d.ImmediateContext);
|
||||||
|
|
||||||
|
Log.Debug("Init OK");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
this.impl.NewFrame();
|
||||||
|
Log.Debug("IMPL NewFrame OK");
|
||||||
|
ImGui.NewFrame();
|
||||||
|
Log.Debug("NewFrame OK");
|
||||||
|
|
||||||
|
ImGui.ShowDemoWindow();
|
||||||
|
Log.Debug("ShowDemoWindow OK");
|
||||||
|
|
||||||
|
ImGui.Render();
|
||||||
|
Log.Debug("Render OK");
|
||||||
|
|
||||||
|
this.impl.RenderDrawData(ImGui.GetDrawData());
|
||||||
|
Log.Debug("RenderDrawData OK");
|
||||||
|
|
||||||
|
return this.presentHook.Original(swapChain, a2, a3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
Dalamud/Game/Internal/DXGI/SwapChainAddressResolver.cs
Normal file
20
Dalamud/Game/Internal/DXGI/SwapChainAddressResolver.cs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.Internal.DXGI
|
||||||
|
{
|
||||||
|
public sealed class SwapChainAddressResolver : BaseAddressResolver {
|
||||||
|
public IntPtr Present { get; private set; }
|
||||||
|
|
||||||
|
protected override void Setup64Bit(SigScanner sig) {
|
||||||
|
var module = Process.GetCurrentProcess().Modules.Cast<ProcessModule>().First(m => m.ModuleName == "dxgi.dll");
|
||||||
|
|
||||||
|
Log.Debug($"Found DXGI: {module.BaseAddress.ToInt64():X}");
|
||||||
|
|
||||||
|
var scanner = new SigScanner(module);
|
||||||
|
Present = scanner.ScanModule("48 89 5C 24 ?? 48 89 74 24 ?? 55 57 41 56 48 8D 6C 24 ??");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
lib/ImGui.NET
Submodule
1
lib/ImGui.NET
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 85b836ac617a39560043c4add1e82e14ef0b1157
|
||||||
Loading…
Add table
Add a link
Reference in a new issue