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

@ -1 +1 @@
Subproject commit 2feb762d72c8717d8ece6a0bf72298776312b2c1
Subproject commit 9e98cb9722bed3129134c7bc2fbe51268b2d6acd

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;
@ -98,24 +99,24 @@ public partial class DisassembledShader
private static readonly char[] Digits = Enumerable.Range(0, 10).Select(c => (char)('0' + c)).ToArray();
public readonly string RawDisassembly;
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 string[] Instructions;
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:
@ -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;
@ -30,33 +31,31 @@ internal static class D3DCompiler
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 = null;
try
{
ID3DBlob? disassembly;
int hr;
fixed (byte* pSrcData = blob)
{
hr = D3DDisassemble(pSrcData, new UIntPtr((uint)blob.Length), (uint)flags, comments, out disassembly);
}
var hr = D3DDisassemble(pSrcData, new UIntPtr((uint)blob.Length), (uint)flags, comments, out disassembly);
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)
{
return ReadOnlySpan<byte>.Empty;
return disassembly == null
? ByteString.Empty
: new ByteString((byte*)disassembly.GetBufferPointer()).Clone();
}
finally
{
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,

@ -1 +1 @@
Subproject commit 3447fe0dc9cfc5f056e1595c6c2413de37db924a
Subproject commit ce41e2b7da65edb25b5308ae41e4ca7d74d75e38

View file

@ -382,7 +382,9 @@ public partial class ModEditWindow
var (label, filename) = tab.Samplers[ idx ];
using var tree = ImRaii.TreeNode( label );
if( !tree )
{
return false;
}
ImRaii.TreeNode( filename, ImGuiTreeNodeFlags.Leaf ).Dispose();
var ret = false;
@ -475,7 +477,6 @@ public partial class ModEditWindow
tab.UpdateSamplers();
tab.UpdateTextureLabels();
return true;
}
private static bool DrawMaterialSamplers( MtrlTab tab, bool disabled )
@ -592,7 +593,7 @@ public partial class ModEditWindow
}
var sb = new StringBuilder( 128 );
sb.Append( $"{prefix}[{firstVector}]{VectorSwizzle( firstComponent, 3 )}" );
sb.Append( $"{prefix}[{firstVector}]{VectorSwizzle( firstComponent, 3 ).TrimEnd()}" );
for( var i = firstVector + 1; i < lastVector; ++i )
{
sb.Append( $", [{i}]" );

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,188 @@
using System;
using System.Collections.Generic;
using Dalamud.Interface.ImGuiFileDialog;
using Dalamud.Utility;
using Lumina.Misc;
using OtterGui;
using Penumbra.GameData.Data;
using Penumbra.GameData.Files;
namespace Penumbra.UI.Classes;
public partial class ModEditWindow
{
private class ShpkTab : IWritable
{
public readonly ShpkFile Shpk;
public string NewMaterialParamName = string.Empty;
public uint NewMaterialParamId = Crc32.Get( string.Empty, 0xFFFFFFFFu );
public short NewMaterialParamStart;
public short NewMaterialParamEnd;
public readonly FileDialogManager FileDialog = ConfigWindow.SetupFileManager();
public readonly string Header;
public readonly string Extension;
public ShpkTab( byte[] bytes )
{
Shpk = new ShpkFile( bytes, true );
Header = $"Shader Package for DirectX {( int )Shpk.DirectXVersion}";
Extension = Shpk.DirectXVersion switch
{
ShpkFile.DxVersion.DirectX9 => ".cso",
ShpkFile.DxVersion.DirectX11 => ".dxbc",
_ => throw new NotImplementedException(),
};
Update();
}
[Flags]
public enum ColorType : byte
{
Unused = 0,
Used = 1,
Continuation = 2,
}
public (string Name, string Tooltip, short Index, ColorType Color)[,] Matrix = null!;
public readonly List< string > MalformedParameters = new();
public readonly HashSet< uint > UsedIds = new(16);
public readonly List< (string Name, short Index) > Orphans = new(16);
public void Update()
{
var materialParams = Shpk.GetConstantById( ShpkFile.MaterialParamsConstantId );
var numParameters = ( ( Shpk.MaterialParamsSize + 0xFu ) & ~0xFu ) >> 4;
Matrix = new (string Name, string Tooltip, short Index, ColorType Color)[numParameters, 4];
MalformedParameters.Clear();
UsedIds.Clear();
foreach( var (param, idx) in Shpk.MaterialParams.WithIndex() )
{
UsedIds.Add( param.Id );
var iStart = param.ByteOffset >> 4;
var jStart = ( param.ByteOffset >> 2 ) & 3;
var iEnd = ( param.ByteOffset + param.ByteSize - 1 ) >> 4;
var jEnd = ( ( param.ByteOffset + param.ByteSize - 1 ) >> 2 ) & 3;
if( ( param.ByteOffset & 0x3 ) != 0 || ( param.ByteSize & 0x3 ) != 0 )
{
MalformedParameters.Add( $"ID: 0x{param.Id:X8}, offset: 0x{param.ByteOffset:X4}, size: 0x{param.ByteSize:X4}" );
continue;
}
if( iEnd >= numParameters )
{
MalformedParameters.Add(
$"{MaterialParamRangeName( materialParams?.Name ?? string.Empty, param.ByteOffset >> 2, param.ByteSize >> 2 )} (ID: 0x{param.Id:X8})" );
continue;
}
for( var i = iStart; i <= iEnd; ++i )
{
var end = i == iEnd ? jEnd : 3;
for( var j = i == iStart ? jStart : 0; j <= end; ++j )
{
var tt = $"{MaterialParamRangeName( materialParams?.Name ?? string.Empty, param.ByteOffset >> 2, param.ByteSize >> 2 ).Item1} (ID: 0x{param.Id:X8})";
Matrix[ i, j ] = ( $"0x{param.Id:X8}", tt, ( short )idx, 0 );
}
}
}
UpdateOrphans( materialParams );
UpdateColors( materialParams );
}
public void UpdateOrphanStart( int orphanStart )
{
var oldEnd = Orphans.Count > 0 ? Orphans[ NewMaterialParamEnd ].Index : -1;
UpdateOrphanStart( orphanStart, oldEnd );
}
private void UpdateOrphanStart( int orphanStart, int oldEnd )
{
var count = Math.Min( NewMaterialParamEnd - NewMaterialParamStart + orphanStart + 1, Orphans.Count );
NewMaterialParamStart = ( short )orphanStart;
var current = Orphans[ NewMaterialParamStart ].Index;
for( var i = NewMaterialParamStart; i < count; ++i )
{
var next = Orphans[ i ].Index;
if( current++ != next )
{
NewMaterialParamEnd = ( short )( i - 1 );
return;
}
if( next == oldEnd )
{
NewMaterialParamEnd = i;
return;
}
}
NewMaterialParamEnd = ( short )( count - 1 );
}
private void UpdateOrphans( ShpkFile.Resource? materialParams )
{
var oldStart = Orphans.Count > 0 ? Orphans[ NewMaterialParamStart ].Index : -1;
var oldEnd = Orphans.Count > 0 ? Orphans[ NewMaterialParamEnd ].Index : -1;
Orphans.Clear();
short newMaterialParamStart = 0;
for( var i = 0; i < Matrix.GetLength( 0 ); ++i )
for( var j = 0; j < 4; ++j )
{
if( !Matrix[ i, j ].Name.IsNullOrEmpty() )
{
continue;
}
Matrix[ i, j ] = ( "(none)", string.Empty, -1, 0 );
var linear = ( short )( 4 * i + j );
if( oldStart == linear )
{
newMaterialParamStart = ( short )Orphans.Count;
}
Orphans.Add( ( $"{materialParams?.Name ?? string.Empty}{MaterialParamName( false, linear )}", linear ) );
}
if( Orphans.Count == 0 )
{
return;
}
UpdateOrphanStart( newMaterialParamStart, oldEnd );
}
private void UpdateColors( ShpkFile.Resource? materialParams )
{
var lastIndex = -1;
for( var i = 0; i < Matrix.GetLength( 0 ); ++i )
{
var usedComponents = ( materialParams?.Used?[ i ] ?? DisassembledShader.VectorComponents.All ) | ( materialParams?.UsedDynamically ?? 0 );
for( var j = 0; j < 4; ++j )
{
var color = ( ( byte )usedComponents & ( 1 << j ) ) != 0
? ColorType.Used
: 0;
if( Matrix[ i, j ].Index == lastIndex || Matrix[ i, j ].Index < 0 )
{
color |= ColorType.Continuation;
}
lastIndex = Matrix[ i, j ].Index;
Matrix[ i, j ].Color = color;
}
}
}
public bool Valid
=> Shpk.Valid;
public byte[] Write()
=> Shpk.Write();
}
}

View file

@ -580,11 +580,11 @@ public partial class ModEditWindow : Window, IDisposable
DrawModelPanel,
() => _mod?.ModPath.FullName ?? string.Empty,
null );
_shaderPackageTab = new FileEditor< ShpkFile >( "Shader Packages", ".shpk",
_shaderPackageTab = new FileEditor< ShpkTab >( "Shader Packages", ".shpk",
() => _editor?.ShpkFiles ?? Array.Empty< Editor.FileRegistry >(),
DrawShaderPackagePanel,
() => _mod?.ModPath.FullName ?? string.Empty,
bytes => new ShpkFile( bytes, true ) );
bytes => new ShpkTab( bytes ) );
_center = new CombinedTexture( _left, _right );
}