-
Notifications
You must be signed in to change notification settings - Fork 232
Render commands and friends #1830
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
81aeda6
e3c9ef1
b7f02b8
0f2118f
67e25b0
9954873
73525a5
ab37087
265c466
62e6622
0f2f956
321e11e
1bd8e90
85331c8
f90eec1
c6b57a9
2c5b0f2
325e3c5
3dac72c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
| } | ||
| 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 | ||
|
|
@@ -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) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just as a note, I would have no idea what to change this to. I guess |
||
| [FieldOffset(0x10)] public void* RenderThread; // Client::Graphics::Kernel::RenderThread | ||
| [FieldOffset(0x28)] private CallbackManager* Unk28; | ||
| [FieldOffset(0x30)] private CallbackManager* Unk30; | ||
|
|
@@ -71,7 +73,7 @@ public unsafe partial struct Device { | |
| // Client::Graphics::Kernel::Device::CallbackManager | ||
| [GenerateInterop] | ||
| [StructLayout(LayoutKind.Explicit, Size = 0x40)] | ||
| public unsafe partial struct CallbackManager { | ||
| public partial struct CallbackManager { | ||
| [FieldOffset(0x8)] public void* Lock; // CRITICAL_SECTION | ||
|
|
||
| [FieldOffset(0x30)] public Entry* Entries; | ||
|
|
@@ -89,7 +91,7 @@ public unsafe partial struct CallbackManager { | |
|
|
||
| // Unsure about the names of things inside CallbackManager though | ||
| [StructLayout(LayoutKind.Explicit, Size = 0x10)] | ||
| public unsafe partial struct Entry { | ||
| public struct Entry { | ||
| [FieldOffset(0x0)] public void* Function; | ||
| [FieldOffset(0x8)] public void* Context; | ||
| } | ||
|
|
@@ -106,55 +108,91 @@ 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 { | ||
| [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; | ||
|
|
||
| [FieldOffset(0x0), Obsolete("Use Type instead.")] public int SwitchType; | ||
| } | ||
|
|
||
| [GenerateInterop] | ||
| [StructLayout(LayoutKind.Explicit, Size = 0x20)] | ||
| public unsafe partial struct RenderCommandViewport { | ||
| [FieldOffset(0x0)] public int SwitchType; | ||
| [FieldOffset(0x04)] public int TopLeftY; | ||
| [FieldOffset(0x08)] public int TopLeftX; | ||
| [FieldOffset(0x0C)] public int BottomRightY; | ||
| [FieldOffset(0x10)] public int BottomRightX; | ||
| public struct RenderCommandViewport { | ||
| [FieldOffset(0x0)] public RenderCommandType Type; | ||
| [FieldOffset(0x4)] public IntRectangle ViewportRect; | ||
| [FieldOffset(0x14)] public float MinDepth; | ||
| [FieldOffset(0x18)] public float MaxDepth; | ||
|
|
||
| [FieldOffset(0x0), Obsolete("Use Type instead.")] public int SwitchType; | ||
| [FieldOffset(0x04), Obsolete("Use ViewportRect.Left.")] public int TopLeftY; | ||
| [FieldOffset(0x08), Obsolete("Use ViewportRect.Top.")] public int TopLeftX; | ||
| [FieldOffset(0x0C), Obsolete("Use ViewportRect.Right.")] public int BottomRightY; | ||
| [FieldOffset(0x10), Obsolete("Use ViewportRect.Bottom.")] public int BottomRightX; | ||
| } | ||
|
|
||
| [GenerateInterop] | ||
| [StructLayout(LayoutKind.Explicit, Size = 0x20)] | ||
| public unsafe partial struct RenderCommandScissorsRect { | ||
| [StructLayout(LayoutKind.Explicit, Size = 0x80)] | ||
| public partial struct RenderCommandMultiViewport { | ||
| [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), FixedSizeArray] internal FixedSizeArray5<IntRectangle> _viewportRects; | ||
| [FieldOffset(0x54), FixedSizeArray] internal FixedSizeArray5<float> _minDepths; | ||
| [FieldOffset(0x68), FixedSizeArray] internal FixedSizeArray5<float> _maxDepths; | ||
| [FieldOffset(0x7C)] public uint ViewportCount; | ||
| } | ||
|
|
||
| [StructLayout(LayoutKind.Explicit, Size = 0x20)] | ||
| public struct RenderCommandScissorsRect { | ||
| [FieldOffset(0x0)] public RenderCommandType Type; | ||
| [FieldOffset(0x4)] public IntRectangle ScissorRect; | ||
|
|
||
| [FieldOffset(0x0), Obsolete("Use Type instead.")] public int SwitchType; | ||
| [FieldOffset(0x4), Obsolete("Use ScissorRect.Left.")] public int Left; | ||
| [FieldOffset(0x8), Obsolete("Use ScissorRect.Top.")] public int Top; | ||
| [FieldOffset(0xC), Obsolete("Use ScissorRect.Right.")] public int Right; | ||
| [FieldOffset(0x10), Obsolete("Use ScissorRect.Bottom.")] 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 { | ||
| [FieldOffset(0x0)] public int SwitchType; | ||
| [FieldOffset(0x4)] public float ClearType; | ||
| public unsafe struct RenderCommandClearDepth { | ||
| [FieldOffset(0x0)] public RenderCommandType Type; | ||
| [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; | ||
| [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(0x1C)] public byte ClearStencil; | ||
| [FieldOffset(0x1D)] public byte StencilReference; | ||
| [FieldOffset(0x20), CExporterTypeForce("D3D11_RECT*")] public IntRectangle* ClearRectanglePtr; // optional, generally points at ClearRectangle if set | ||
| [FieldOffset(0x28)] public IntRectangle ClearRectangle; | ||
| [FieldOffset(0x38)] public float MinZ; | ||
| [FieldOffset(0x3C)] public float MaxZ; | ||
|
|
||
| [FieldOffset(0x0), Obsolete("Use Type instead.")] public int SwitchType; | ||
| [FieldOffset(0x4), Obsolete("This is incorrect. Use ClearFlags.")] public float ClearType; | ||
| [FieldOffset(0x20), Obsolete("This is incorrect. Use ClearRectanglePtr.")] public int ClearCheck; | ||
| [FieldOffset(0x28), Obsolete("This is incorrect. Use ClearRectangle.Left instead.")] public float Left; | ||
| [FieldOffset(0x2C), Obsolete("This is incorrect. Use ClearRectangle.Top instead.")] public float Top; | ||
| [FieldOffset(0x30), Obsolete("This is incorrect. Use ClearRectangle.Right instead.")] public float Width; | ||
| [FieldOffset(0x34), Obsolete("This is incorrect. Use ClearRectangle.Bottom instead.")] public float Height; | ||
| } | ||
| 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 | ||
|
|
@@ -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; | ||
|
|
||
| [FieldOffset(0xBE8), CExporterTypeForce("ID3D11DeviceContext*", true)] 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; | ||
| [FieldOffset(0x17B8), CExporterTypeForce("ID3D11DeviceContext*", true)] public void* D3D11DeviceContext_2; | ||
|
|
||
| //[FieldOffset(0x1D70)] public InputLayout* CurrentInputLayout; | ||
| [FieldOffset(0x17D8), CExporterTypeForce("D3D11_PRIMITIVE_TOPOLOGY", true)] 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 void SetVertexShader(VertexShader* vertexShader, void** constantBuffers); | ||
|
|
||
| [MemberFunction("E8 ?? ?? ?? ?? 4D 8B 46 78")] | ||
| public partial void 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); | ||
|
Comment on lines
+87
to
+91
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Process and Preprocess have the same sig? |
||
|
|
||
| [FieldOffset(0xBE8)] public void* D3D11DeviceContext; | ||
| [MemberFunction("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 0F B6 83 ?? ?? ?? ?? 3C 01 73 70")] | ||
| public partial void 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); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should commandType use the enum?