Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions FFXIVClientStructs/FFXIV/Client/Graphics/Kernel/Context.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;

/// <summary>
/// Records rendering commands to be executed later by the <see cref="ImmediateContext"/>.
/// </summary>
/// <remarks>
/// Threads have their own Context, accessed via <see cref="ThreadLocals.GraphicsKernelContext"/>.
/// </remarks>
[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0x2F78)]
public unsafe partial struct Context {
[BitField<byte>(nameof(CurrentSubViewIndex), 28, 4)]
[FieldOffset(0x008)] private uint _flags;
[FieldOffset(0x00C)] public int ViewIndex;
[FieldOffset(0x010)] public void* CommandAllocationBase;

[FieldOffset(0x840)] public ulong CommandAllocationUsedSize;
[FieldOffset(0x848)] public ulong AllocationBase;
[FieldOffset(0x850)] public ulong AllocationUsedSize;

[MemberFunction("4C 8B D1 4C 8D 42 0F")]
public partial void* AllocateCommand(ulong size);

[MemberFunction("4C 8B C9 4D 8D 50 0F")]
public partial void* AllocateSpecificCommand(int commandType, ulong size);

[MemberFunction("E8 ?? ?? ?? ?? 8B 6E 6C")]
public partial void PushBackCommand(void* command);

[MemberFunction("E8 ?? ?? ?? ?? 8D 56 38")]
public partial void SetRenderTargets(int renderTargetCount, Texture** renderTargetTextures, Texture* depthStencilTexture, short a4, short a5, short a6, short a7); // last params believed to be a rectangle
}
73 changes: 64 additions & 9 deletions FFXIVClientStructs/FFXIV/Client/Graphics/Kernel/Device.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using FFXIVClientStructs.FFXIV.Common.Math;

namespace FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;

// Client::Graphics::Kernel::Device
Expand All @@ -10,7 +12,7 @@ public unsafe partial struct Device {
[StaticAddress("48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 80 7B 08 00", 3, isPointer: true)]
public static partial Device* Instance();

[FieldOffset(0x8)] public void* ContextArray; // Client::Graphics::Kernel::Context array
[FieldOffset(0x8)] public void* ContextArray; // TODO: We have a struct for this now (breaking change)
[FieldOffset(0x10)] public void* RenderThread; // Client::Graphics::Kernel::RenderThread
[FieldOffset(0x28)] private CallbackManager* Unk28;
[FieldOffset(0x30)] private CallbackManager* Unk30;
Expand Down Expand Up @@ -106,55 +108,108 @@ public unsafe struct RenderCommandBufferGroup {
[FieldOffset(0x8), CExporterUnion("RenderCommand")] public RenderCommandClearDepth* ClearDepthCommand;
}

public enum RenderCommandType : int {
SetTarget = 0,
Viewport = 1,
MultiViewport = 2,
ScissorRect = 3,
Clear = 4,
}

[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0x40)]
public unsafe partial struct RenderCommandSetTarget {
[Obsolete("Use Type instead.")]
[FieldOffset(0x0)] public int SwitchType;
[FieldOffset(0x0)] public RenderCommandType Type;
[FieldOffset(0x4)] public int RenderTargetCount;
[FieldOffset(0x8), FixedSizeArray] internal FixedSizeArray4<Pointer<Texture>> _renderTargets;
[FieldOffset(0x28)] public Texture* DepthBuffer;
[FieldOffset(0x8), FixedSizeArray] internal FixedSizeArray5<Pointer<Texture>> _renderTargets;
[FieldOffset(0x30)] public Texture* DepthBuffer;
[FieldOffset(0x38)] private float Unk0;
[FieldOffset(0x3C)] private float Unk1;
}

[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0x20)]
public unsafe partial struct RenderCommandViewport {
[Obsolete("Use Type instead.")]
[FieldOffset(0x0)] public int SwitchType;
[FieldOffset(0x0)] public RenderCommandType Type;
[FieldOffset(0x4)] public IntRectangle ViewportRect;
[Obsolete("Use ViewportRect.Left.")]
[FieldOffset(0x04)] public int TopLeftY;
[Obsolete("Use ViewportRect.Top.")]
[FieldOffset(0x08)] public int TopLeftX;
[Obsolete("Use ViewportRect.Right.")]
[FieldOffset(0x0C)] public int BottomRightY;
[Obsolete("Use ViewportRect.Bottom.")]
[FieldOffset(0x10)] public int BottomRightX;
[FieldOffset(0x14)] public float MinDepth;
[FieldOffset(0x18)] public float MaxDepth;
}

[StructLayout(LayoutKind.Explicit, Size = 0x80)]
public unsafe partial struct RenderCommandMultiViewport {
[FieldOffset(0x0)] public int SwitchType;
[FieldOffset(0x4), FixedSizeArray] internal FixedSizeArray5<IntRectangle> _viewportRects;
[FieldOffset(0x54), FixedSizeArray] internal FixedSizeArray5<float> _minDepths;
[FieldOffset(0x68), FixedSizeArray] internal FixedSizeArray5<float> _maxDepths;
[FieldOffset(0x7C)] public uint ViewportCount;
}

[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0x20)]
public unsafe partial struct RenderCommandScissorsRect {
[Obsolete("Use Type instead.")]
[FieldOffset(0x0)] public int SwitchType;
[FieldOffset(0x0)] public RenderCommandType Type;
[FieldOffset(0x4)] public IntRectangle ScissorRect;
[Obsolete("Use ScissorRect.Left.")]
[FieldOffset(0x4)] public int Left;
[Obsolete("Use ScissorRect.Top.")]
[FieldOffset(0x8)] public int Top;
[Obsolete("Use ScissorRect.Right.")]
[FieldOffset(0xC)] public int Right;
[Obsolete("Use ScissorRect.Bottom.")]
[FieldOffset(0x10)] public int Bottom;
}

public enum ClearFlags : uint {
None = 0,
Color = (1 << 0),
Depth = (1 << 1),
Stencil = (1 << 2),
}

[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0x40)]
public unsafe partial struct RenderCommandClearDepth {
[Obsolete("Use Type instead.")]
[FieldOffset(0x0)] public int SwitchType;
[FieldOffset(0x0)] public RenderCommandType Type;
[Obsolete("This is incorrect. Use ClearFlags.")]
[FieldOffset(0x4)] public float ClearType;
[FieldOffset(0x4)] public ClearFlags ClearFlags;
[FieldOffset(0x8)] public float ColorB;
[FieldOffset(0xC)] public float ColorG;
[FieldOffset(0x10)] public float ColorR;
[FieldOffset(0x14)] public float ColorA;
[FieldOffset(0x18)] public float ClearDepth;
[FieldOffset(0x1C)] public int ClearStencil;
[FieldOffset(0x1C)] public byte ClearStencil;
[FieldOffset(0x1D)] public byte StencilReference;
[Obsolete("This is incorrect. Use ClearRectangle.")]
[FieldOffset(0x20)] public int ClearCheck;
[FieldOffset(0x24)] public float Top;
[CExporterTypeForce("D3D11_RECT*")]
[FieldOffset(0x20)] public IntRectangle* ClearRectanglePtr; // optional, points at ClearRectangle if set
[FieldOffset(0x28)] public IntRectangle ClearRectangle;
[Obsolete("This is incorrect. Use ClearRectangle.Left instead.")]
[FieldOffset(0x28)] public float Left;
[FieldOffset(0x2C)] public float Width;
[FieldOffset(0x30)] public float Height;
[FieldOffset(0x34)] public float MinZ;
[FieldOffset(0x38)] public float MaxZ;
[Obsolete("This is incorrect. Use ClearRectangle.Top instead.")]
[FieldOffset(0x2C)] public float Top;
[Obsolete("This is incorrect. Use ClearRectangle.Right instead.")]
[FieldOffset(0x30)] public float Width;
[Obsolete("This is incorrect. Use ClearRectangle.Bottom instead.")]
[FieldOffset(0x34)] public float Height;
[FieldOffset(0x38)] public float MinZ;
[FieldOffset(0x3C)] public float MaxZ;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using FFXIVClientStructs.FFXIV.Common.Math;

namespace FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;

// Client::Graphics::Kernel::ImmediateContext
Expand All @@ -8,10 +10,89 @@ namespace FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
public unsafe partial struct ImmediateContext {
// Offset 0 is ID3D11DeviceContext

// <remark>
// Reset and assigned each rendered frame from Device->SwapChain->BackBuffer
// </remark>
[FieldOffset(0x08)] public Rectangle CurrentScissorRect;

[Obsolete("Not necessarily the backbuffer, just the current primary render target. Prefer CurrentRenderTargets.")]
[FieldOffset(0x28)] public Texture* BackBufferReference;
/// <summary>
/// The currently bound render targets.
/// </summary>
[FieldOffset(0x28)] internal FixedSizeArray5<Pointer<Texture>> _currentRenderTargets;
/// <summary>
/// The currently bound depth stencil buffer, if any.
/// </summary>
[FieldOffset(0x50)] public Texture* CurrentDepthStencilBuffer;

[FieldOffset(0xAC)] public uint CurrentDepthState; // The 5 bits of depth state in PackedDepthStencilDesc with the stencil fields masked out
[FieldOffset(0xB0)] public PackedDepthStencilDesc CurrentStencilState; // With the depth fields masked out
// 0xC8: InputLayoutDesc

[FieldOffset(0xD0)] public VertexShader* CurrentVertexShader;
[FieldOffset(0x1B8)] public PixelShader* CurrentPixelShader;

// Certain types of complex clearing needs to be done by manually drawing to the render targets & depth buffer.
[FieldOffset(0x700)] public VertexShader* ManualClearQuadVertexShader;
[FieldOffset(0x708)] public PixelShader* ManualClearQuadPixelShader;
// 0x710: ManualClearQuad???
// 0x718: ManualClearQuadInputLayoutDesc
[FieldOffset(0x730)] public GeometryShader* CurrentGeometryShader;
[FieldOffset(0xB20)] public HullShader* CurrentHullShader;

[CExporterTypeForce("ID3D11DeviceContext*", true)]
[FieldOffset(0xBE8)] public void* D3D11DeviceContext;

[FieldOffset(0xF10)] public DomainShader* CurrentDomainShader;

[FieldOffset(0x17B3)] public byte BlendStateFlag; // Might be a bool to force creation of an underlying ID3D11BlendState*
[FieldOffset(0x17B4)] public PackedBlendStateDesc CurrentBlendState;
[CExporterTypeForce("ID3D11DeviceContext*", true)]
[FieldOffset(0x17B8)] public void* D3D11DeviceContext_2;

//[FieldOffset(0x1D70)] public InputLayout* CurrentInputLayout;
[CExporterTypeForce("D3D11_PRIMITIVE_TOPOLOGY", true)]
[FieldOffset(0x17D8)] public int CurrentPrimitiveTopology;

[MemberFunction("E8 ?? ?? ?? ?? 49 8D 47 58")]
public partial void SetBlendState(PackedBlendStateDesc blendState);

[MemberFunction("E8 ?? ?? ?? ?? 41 8B 56 1C 48 8B CE")]
public partial void SetDepthStencilState(byte obfuscatedDepthState, PackedDepthStencilDesc stencilState);

// Along with the given packed rasterizer state, the following constant values are also used:
// FrontCounterClockwise = true
// DepthClipEnable = true
// DepthBiasClamp = 100.0f
// AntialiasedLineEnable = false
[MemberFunction("E8 ?? ?? ?? ?? 49 8B 46 20 48 8B CE")]
public partial void SetRasterizerState(PackedRasterizerStateDesc rasterizerState);

[MemberFunction("E8 ?? ?? ?? ?? 4D 8B 46 68")]
public partial ulong SetVertexShader(VertexShader* vertexShader, void** constantBuffers);

[MemberFunction("E8 ?? ?? ?? ?? 4D 8B 46 78")]
public partial ulong SetPixelShader(PixelShader* pixelShader, void** constantBuffers);

[MemberFunction("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 8B 57 7C")]
public partial void SetViewport(IntRectangle* viewportRectangle, float minDepth, float maxDepth);

[MemberFunction("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 48 8B D7 48 8B CB E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 48 83 7F")]
public partial void SetMultiViewports(uint viewportCount, IntRectangle* viewports, float* minDepths, float* maxDepths);

[MemberFunction("E9 ?? ?? ?? ?? 48 8B 4A 10")]
public partial void SetDefaultState();

[MemberFunction("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 48 83 7F ?? ?? 0F 84 ?? ?? ?? ?? 48 83 7F")]
public partial void DoClearCommandViaDraw(RenderCommandClearDepth* clearCommand);

[MemberFunction("48 89 6C 24 ?? 56 48 83 EC 40 48 83 7A")] // inlined in some places
public partial void DoClearCommand(RenderCommandClearDepth* clearCommand);

[MemberFunction("E8 ?? ?? ?? ?? 48 8B 7B 18 45 33 FF")]
public partial void ProcessCommands(RenderCommandBufferGroup* renderCommands, uint renderCommandCount);

[MemberFunction("E8 ?? ?? ?? ?? 48 8B 7B 18 45 33 FF")]
public partial void PreprocessCommands(RenderCommandBufferGroup* renderCommands, uint renderCommandCount);

[MemberFunction("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 0F B6 83 ?? ?? ?? ?? 3C 01 73 70")]
public partial RenderCommandBufferGroup* ExecuteCommands();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
namespace FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;

/// <summary>
/// Contains blending configuration for the renderer.
/// </summary>
/// <remarks>
/// Rather than manage a bunch of pointers to blend state objects, render commands accept a
/// description of the desired blend state packed into 32 bits, which is copied around
/// by value and eventually a real D3D blend state object is created within the
/// <see cref="ImmediateContext"/> as needed.
/// </remarks>
[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0x04)]
public unsafe partial struct PackedBlendStateDesc {

// E (BlendEnabled)
// OOO (BlendOpMinusOne)
// SSSS (SrcBlendMinusOne)
// DDDD (DestBlendMinusOne)
// ooo (BlendOpAlphaMinusOne)
// sss s (SrcBlendAlphaMinusOne)
// ddd d (DestBlendAlphaMinusOne)
// MMM M (RenderTargetWriteMask)
// ---- - (--masked out--)
// xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
[BitField<bool>(nameof(BlendEnable), 0, 1)]
[BitField<byte>(nameof(BlendOpMinusOne), 1, 3)]
[BitField<byte>(nameof(SrcBlendMinusOne), 4, 4)]
[BitField<byte>(nameof(DestBlendMinusOne), 8, 4)]
[BitField<byte>(nameof(BlendOpAlphaMinusOne), 12, 3)]
[BitField<byte>(nameof(SrcBlendAlphaMinusOne), 15, 4)]
[BitField<byte>(nameof(DestBlendAlphaMinusOne), 19, 4)]
[BitField<byte>(nameof(RenderTargetWriteMask), 23, 4)]
[FieldOffset(0x00)] internal uint _value;

// D3D11_BLEND_OP
private partial byte BlendOpMinusOne { get; set; }
public byte BlendOp {
get => (byte)(BlendOpMinusOne + 1);
set => BlendOpMinusOne = (byte)(value - 1);
}

// D3D11_BLEND
private partial byte SrcBlendMinusOne { get; set; }
public byte SrcBlend {
get => (byte)(SrcBlendMinusOne + 1);
set => SrcBlendMinusOne = (byte)(value - 1);
}

// D3D11_BLEND
private partial byte DestBlendMinusOne { get; set; }
public byte DestBlend {
get => (byte)(DestBlendMinusOne + 1);
set => DestBlendMinusOne = (byte)(value - 1);
}

// D3D11_BLEND_OP
private partial byte BlendOpAlphaMinusOne { get; set; }
public byte BlendOpAlpha {
get => (byte)(BlendOpAlphaMinusOne + 1);
set => BlendOpAlphaMinusOne = (byte)(value - 1);
}

// D3D11_BLEND
private partial byte SrcBlendAlphaMinusOne { get; set; }
public byte SrcBlendAlpha {
get => (byte)(SrcBlendAlphaMinusOne + 1);
set => SrcBlendAlphaMinusOne = (byte)(value - 1);
}

// D3D11_BLEND
private partial byte DestBlendAlphaMinusOne { get; set; }
public byte DestBlendAlpha {
get => (byte)(DestBlendAlphaMinusOne + 1);
set => DestBlendAlphaMinusOne = (byte)(value - 1);
}
}
Loading
Loading