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
}
35 changes: 21 additions & 14 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 @@ -111,8 +113,8 @@ public unsafe struct RenderCommandBufferGroup {
public unsafe partial struct RenderCommandSetTarget {
[FieldOffset(0x0)] public int SwitchType;
[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;
}
Expand All @@ -133,28 +135,33 @@ public unsafe partial struct RenderCommandViewport {
[StructLayout(LayoutKind.Explicit, Size = 0x20)]
public unsafe partial struct RenderCommandScissorsRect {
[FieldOffset(0x0)] public int SwitchType;
[FieldOffset(0x4)] public int Left;
[FieldOffset(0x8)] public int Top;
[FieldOffset(0xC)] public int Right;
[FieldOffset(0x10)] public int Bottom;
[FieldOffset(0x4)] public Rectangle Rectangle;
}

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 {
[FieldOffset(0x0)] public int SwitchType;
[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(0x20)] public int ClearCheck;
[FieldOffset(0x24)] public float Top;
[CExporterTypeForce("D3D11_VIEWPORT*")]
[FieldOffset(0x20)] public void* ClearRectangle; // optional
[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;
[FieldOffset(0x2C)] public float Top;
[FieldOffset(0x30)] public float Width;
[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,86 @@ 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(Rectangle* viewportRectangle);

[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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
namespace FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;

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

// D (DepthEnable)
// d (DepthWriteMask) D3D11_DEPTH_WRITE_MASK
// f ff (DepthFuncMinusOne)
// - ---- --- (--masked out--)
// SSS (BackFaceStencilFuncMinusOne)
// fff (BackFaceStencilFailOpMinusOne)
// DD D (BackFaceStencilDepthFailOpMinusOne)
// P PP (BackFaceStencilPassOpMinusOne)
// S (StencilEnable)
// s ss (FrontFaceStencilFuncMinusOne)
// FFF (FrontFaceStencilFailOpMinusOne)
// xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
[BitField<bool>(nameof(DepthEnable), 0, 1)]
[BitField<bool>(nameof(DepthWriteMask), 1, 1)]
[BitField<byte>(nameof(DepthFuncMinusOne), 2, 3)]
[BitField<byte>(nameof(BackFaceStencilFuncMinusOne), 13, 3)]
[BitField<byte>(nameof(BackFaceStencilFailOpMinusOne), 16, 3)]
[BitField<byte>(nameof(BackFaceStencilDepthFailOpMinusOne), 19, 3)]
[BitField<byte>(nameof(BackFaceStencilPassOpMinusOne), 22, 3)]
[BitField<bool>(nameof(StencilEnable), 25, 1)]
[BitField<byte>(nameof(FrontFaceStencilFuncMinusOne), 26, 3)]
[BitField<byte>(nameof(FrontFaceStencilFailOpMinusOne), 29, 3)]
[FieldOffset(0x00)] internal uint _firstPart;

// - (--masked out--)
// D (BackFaceStencilIndependent)
// d dd (FrontFaceStencilDepthFailOpMinusOne)
// ppp (FrontFaceStencilPassOpMinusOne)
// ???? ???? (--often masked out, unsure--)
// RRRR RRRR (StencilReadMask)
// WWWW WWWW (StencilWriteMask)
// xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
[BitField<bool>(nameof(BackFaceStencilIndependent), 1, 1)]
[BitField<byte>(nameof(FrontFaceStencilDepthFailOpMinusOne), 2, 3)]
[BitField<byte>(nameof(FrontFaceStencilPassOpMinusOne), 5, 3)]
[FieldOffset(0x04)] internal byte _secondPart;

[FieldOffset(0x06)] public byte StencilReadMask;
[FieldOffset(0x07)] public byte StencilWriteMask;

private partial byte DepthFuncMinusOne { get; set; }
public byte DepthFunc {
get => (byte)(DepthFuncMinusOne + 1);
set => DepthFuncMinusOne = (byte)(value - 1);
}

private partial byte BackFaceStencilFuncMinusOne { get; set; }
public byte BackFaceStencilFunc {
get => (byte)(BackFaceStencilFuncMinusOne + 1);
set => BackFaceStencilFuncMinusOne = (byte)(value - 1);
}

private partial byte BackFaceStencilFailOpMinusOne { get; set; }
public byte BackFaceStencilFailOp {
get => (byte)(BackFaceStencilFailOpMinusOne + 1);
set => BackFaceStencilFailOpMinusOne = (byte)(value - 1);
}

private partial byte BackFaceStencilDepthFailOpMinusOne { get; set; }
public byte BackFaceStencilDepthFailOp {
get => (byte)(BackFaceStencilDepthFailOpMinusOne + 1);
set => BackFaceStencilDepthFailOpMinusOne = (byte)(value - 1);
}

private partial byte BackFaceStencilPassOpMinusOne { get; set; }
public byte BackFaceStencilPassOp {
get => (byte)(BackFaceStencilPassOpMinusOne + 1);
set => BackFaceStencilPassOpMinusOne = (byte)(value + 1);
}

private partial byte FrontFaceStencilFuncMinusOne { get; set; }
public byte FrontFaceStencilFunc {
get => (byte)(FrontFaceStencilFuncMinusOne + 1);
set => FrontFaceStencilFuncMinusOne = (byte)(value - 1);
}

private partial byte FrontFaceStencilFailOpMinusOne { get; set; }
public byte FrontFaceStencilFailOp {
get => (byte)(FrontFaceStencilFailOpMinusOne + 1);
set => FrontFaceStencilFailOpMinusOne = (byte)(value - 1);
}

private partial byte FrontFaceStencilDepthFailOpMinusOne { get; set; }
public byte FrontFaceStencilDepthFailOp {
get => (byte)(FrontFaceStencilDepthFailOpMinusOne + 1);
set => FrontFaceStencilDepthFailOpMinusOne = (byte)(value - 1);
}

private partial byte FrontFaceStencilPassOpMinusOne { get; set; }
public byte FrontFaceStencilPassOp {
get => (byte)(FrontFaceStencilPassOpMinusOne + 1);
set => FrontFaceStencilPassOpMinusOne = (byte)(value + 1);
}
}
Loading
Loading