Redesign Shpk tab.

This commit is contained in:
Ottermandias 2023-03-01 18:03:59 +01:00
parent 7ae6d0a348
commit e62b0155d4
8 changed files with 792 additions and 569 deletions

View file

@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Penumbra.GameData.Interop;
using Penumbra.String;
namespace Penumbra.GameData.Data;
@ -96,26 +97,26 @@ public partial class DisassembledShader
[GeneratedRegex(@"^\s*sample_\S*\s+[^.]+\.([wxyz]+),[^,]+,\s*t(\d+)\.([wxyz]+)", RegexOptions.NonBacktracking)]
private static partial Regex Sm5TextureUsageRegex();
private static readonly char[] Digits = Enumerable.Range(0, 10).Select(c => (char) ('0' + c)).ToArray();
private static readonly char[] Digits = Enumerable.Range(0, 10).Select(c => (char)('0' + c)).ToArray();
public readonly string RawDisassembly;
public readonly uint ShaderModel;
public readonly ShaderStage Stage;
public readonly string BufferDefinitions;
public readonly ResourceBinding[] ResourceBindings;
public readonly InputOutput[] InputSignature;
public readonly InputOutput[] OutputSignature;
public readonly string[] Instructions;
public readonly ByteString RawDisassembly;
public readonly uint ShaderModel;
public readonly ShaderStage Stage;
public readonly string BufferDefinitions;
public readonly ResourceBinding[] ResourceBindings;
public readonly InputOutput[] InputSignature;
public readonly InputOutput[] OutputSignature;
public readonly IReadOnlyList<ByteString> Instructions;
public DisassembledShader(string rawDisassembly)
public DisassembledShader(ByteString rawDisassembly)
{
RawDisassembly = rawDisassembly;
var lines = rawDisassembly.Split('\n');
Instructions = Array.FindAll(lines, ln => !ln.StartsWith("//") && ln.Length > 0);
var shaderModel = Instructions[0].Trim().Split('_');
Stage = (ShaderStage)(byte)char.ToUpper(shaderModel[0][0]);
ShaderModel = (uint.Parse(shaderModel[1]) << 8) | uint.Parse(shaderModel[2]);
var header = PreParseHeader(lines.AsSpan()[..Array.IndexOf(lines, Instructions[0])]);
var lines = rawDisassembly.Split((byte) '\n');
Instructions = lines.FindAll(ln => !ln.StartsWith("//"u8) && ln.Length > 0);
var shaderModel = Instructions[0].Trim().Split((byte) '_');
Stage = (ShaderStage)(byte)char.ToUpper((char) shaderModel[0][0]);
ShaderModel = (uint.Parse(shaderModel[1].ToString()) << 8) | uint.Parse(shaderModel[2].ToString());
var header = PreParseHeader(lines.Take(lines.IndexOf(Instructions[0])).Select(l => l.ToString()).ToArray());
switch (ShaderModel >> 8)
{
case 3:
@ -142,8 +143,8 @@ public partial class DisassembledShader
private static void ParseSm3Header(Dictionary<string, string[]> header, out string bufferDefinitions,
out ResourceBinding[] resourceBindings, out InputOutput[] inputSignature, out InputOutput[] outputSignature)
{
bufferDefinitions = header.TryGetValue("Parameters", out var rawParameters)
? string.Join('\n', rawParameters)
bufferDefinitions = header.TryGetValue("Parameters", out var rawParameters)
? string.Join('\n', rawParameters)
: string.Empty;
if (header.TryGetValue("Registers", out var rawRegisters))
{
@ -176,7 +177,7 @@ public partial class DisassembledShader
outputSignature = Array.Empty<InputOutput>();
}
private static void ParseSm3ResourceUsage(string[] instructions, ResourceBinding[] resourceBindings)
private static void ParseSm3ResourceUsage(IReadOnlyList<ByteString> instructions, ResourceBinding[] resourceBindings)
{
var cbIndices = new Dictionary<uint, int>();
var tIndices = new Dictionary<uint, int>();
@ -201,10 +202,11 @@ public partial class DisassembledShader
foreach (var instruction in instructions)
{
var trimmed = instruction.Trim();
if (trimmed.StartsWith("def") || trimmed.StartsWith("dcl"))
if (trimmed.StartsWith("def"u8) || trimmed.StartsWith("dcl"u8))
continue;
foreach (Match cbMatch in Sm3ConstantBufferUsageRegex().Matches(instruction))
var instructionString = instruction.ToString();
foreach (Match cbMatch in Sm3ConstantBufferUsageRegex().Matches(instructionString))
{
var buffer = uint.Parse(cbMatch.Groups[1].Value);
if (cbIndices.TryGetValue(buffer, out var i))
@ -217,7 +219,7 @@ public partial class DisassembledShader
}
}
var tMatch = Sm3TextureUsageRegex().Match(instruction);
var tMatch = Sm3TextureUsageRegex().Match(instructionString);
if (tMatch.Success)
{
var texture = uint.Parse(tMatch.Groups[1].Value);
@ -307,7 +309,7 @@ public partial class DisassembledShader
}
}
private static void ParseSm5ResourceUsage(string[] instructions, ResourceBinding[] resourceBindings)
private static void ParseSm5ResourceUsage(IReadOnlyList<ByteString> instructions, ResourceBinding[] resourceBindings)
{
var cbIndices = new Dictionary<uint, int>();
var tIndices = new Dictionary<uint, int>();
@ -331,10 +333,11 @@ public partial class DisassembledShader
foreach (var instruction in instructions)
{
var trimmed = instruction.Trim();
if (trimmed.StartsWith("def") || trimmed.StartsWith("dcl"))
if (trimmed.StartsWith("def"u8) || trimmed.StartsWith("dcl"u8))
continue;
foreach (Match cbMatch in Sm5ConstantBufferUsageRegex().Matches(instruction))
var instructionString = instruction.ToString();
foreach (Match cbMatch in Sm5ConstantBufferUsageRegex().Matches(instructionString))
{
var buffer = uint.Parse(cbMatch.Groups[1].Value);
if (cbIndices.TryGetValue(buffer, out var i))
@ -352,7 +355,7 @@ public partial class DisassembledShader
}
}
var tMatch = Sm5TextureUsageRegex().Match(instruction);
var tMatch = Sm5TextureUsageRegex().Match(instructionString);
if (tMatch.Success)
{
var texture = uint.Parse(tMatch.Groups[2].Value);

View file

@ -1,6 +1,7 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using Penumbra.String;
namespace Penumbra.GameData.Interop;
@ -20,43 +21,41 @@ internal static class D3DCompiler
[Flags]
public enum DisassembleFlags : uint
{
EnableColorCode = 1,
EnableDefaultValuePrints = 2,
EnableColorCode = 1,
EnableDefaultValuePrints = 2,
EnableInstructionNumbering = 4,
EnableInstructionCycle = 8,
DisableDebugInfo = 16,
EnableInstructionOffset = 32,
InstructionOnly = 64,
PrintHexLiterals = 128,
EnableInstructionCycle = 8,
DisableDebugInfo = 16,
EnableInstructionOffset = 32,
InstructionOnly = 64,
PrintHexLiterals = 128,
}
public static unsafe string Disassemble(ReadOnlySpan<byte> blob, DisassembleFlags flags = 0, string comments = "")
public static unsafe ByteString Disassemble(ReadOnlySpan<byte> blob, DisassembleFlags flags = 0, string comments = "")
{
ID3DBlob? disassembly;
int hr;
fixed (byte* pSrcData = blob)
ID3DBlob? disassembly = null;
try
{
hr = D3DDisassemble(pSrcData, new UIntPtr((uint)blob.Length), (uint)flags, comments, out disassembly);
fixed (byte* pSrcData = blob)
{
var hr = D3DDisassemble(pSrcData, new UIntPtr((uint)blob.Length), (uint)flags, comments, out disassembly);
Marshal.ThrowExceptionForHR(hr);
}
return disassembly == null
? ByteString.Empty
: new ByteString((byte*)disassembly.GetBufferPointer()).Clone();
}
Marshal.ThrowExceptionForHR(hr);
var ret = Encoding.UTF8.GetString(BlobContents(disassembly));
GC.KeepAlive(disassembly);
return ret;
}
private static unsafe ReadOnlySpan<byte> BlobContents(ID3DBlob? blob)
{
if (blob == null)
finally
{
return ReadOnlySpan<byte>.Empty;
if (disassembly != null)
Marshal.FinalReleaseComObject(disassembly);
}
return new ReadOnlySpan<byte>(blob.GetBufferPointer(), (int)blob.GetBufferSize().ToUInt32());
}
[PreserveSig]
[DllImport("D3DCompiler_47.dll")]
private extern static unsafe int D3DDisassemble(
private static extern unsafe int D3DDisassemble(
[In] byte* pSrcData,
[In] UIntPtr srcDataSize,
uint flags,