From 4066581132d83d8566e2b96ffc54bb49d741ac16 Mon Sep 17 00:00:00 2001 From: AndresTraks Date: Sun, 11 Apr 2021 19:30:51 +0300 Subject: [PATCH] Parse command line options, fix swizzle --- CommandLineOptions.cs | 38 +++++++++++++++ DirectXShaderModel/Instruction.cs | 46 +++++++++---------- DirectXShaderModel/ShaderModel.cs | 6 +-- .../ShaderAssembly/ps_dot_product2_add.asm | 2 +- .../ShaderAssembly/ps_float4_construct2.asm | 2 +- .../ShaderAssembly/ps_negate_absolute.asm | 2 +- .../vs_matrix22_vector2_multiply.asm | 2 +- .../vs_vector2_matrix22_multiply.asm | 4 +- HlslDecompiler.csproj | 1 + Program.cs | 29 ++++++------ README.md | 33 +++++++++++++ 11 files changed, 117 insertions(+), 48 deletions(-) create mode 100644 CommandLineOptions.cs diff --git a/CommandLineOptions.cs b/CommandLineOptions.cs new file mode 100644 index 0000000..192a8f4 --- /dev/null +++ b/CommandLineOptions.cs @@ -0,0 +1,38 @@ +using System; + +namespace HlslDecompiler +{ + public class CommandLineOptions + { + public string InputFilename { get; } + public bool DoAstAnalysis { get; } + + public static CommandLineOptions Parse(string[] args) + { + return new CommandLineOptions(args); + } + + private CommandLineOptions(string[] args) + { + foreach (string arg in args) + { + if (arg.StartsWith("--")) + { + string option = arg.Substring(2); + if (option == "ast") + { + DoAstAnalysis = true; + } + else + { + Console.WriteLine("Unknown option: --" + option); + } + } + else + { + InputFilename = arg; + } + } + } + } +} diff --git a/DirectXShaderModel/Instruction.cs b/DirectXShaderModel/Instruction.cs index 673dbd5..50e5e82 100644 --- a/DirectXShaderModel/Instruction.cs +++ b/DirectXShaderModel/Instruction.cs @@ -339,42 +339,42 @@ public byte[] GetSourceSwizzleComponents(int srcIndex) public string GetSourceSwizzleName(int srcIndex) { - int swizzleLength; + int destinationMask; if (Opcode == Opcode.Dp4) { - swizzleLength = 4; + destinationMask = 15; } else if (Opcode == Opcode.Dp3) { - swizzleLength = 3; - } - else if (HasDestination) - { - swizzleLength = GetDestinationMaskLength(); + destinationMask = 7; } else { - swizzleLength = 4; + destinationMask = GetDestinationWriteMask(); } - string swizzleName = ""; byte[] swizzle = GetSourceSwizzleComponents(srcIndex); - for (int i = 0; i < swizzleLength; i++) + + string swizzleName = ""; + for (int i = 0; i < 4; i++) { - switch (swizzle[i]) + if ((destinationMask & (1 << i)) != 0) { - case 0: - swizzleName += "x"; - break; - case 1: - swizzleName += "y"; - break; - case 2: - swizzleName += "z"; - break; - case 3: - swizzleName += "w"; - break; + switch (swizzle[i]) + { + case 0: + swizzleName += "x"; + break; + case 1: + swizzleName += "y"; + break; + case 2: + swizzleName += "z"; + break; + case 3: + swizzleName += "w"; + break; + } } } switch (swizzleName) diff --git a/DirectXShaderModel/ShaderModel.cs b/DirectXShaderModel/ShaderModel.cs index e76eedb..698658c 100644 --- a/DirectXShaderModel/ShaderModel.cs +++ b/DirectXShaderModel/ShaderModel.cs @@ -62,7 +62,7 @@ public IList ParseConstantTable() int numConstants = ctabReader.ReadInt32(); long constantInfoPosition = ctabReader.ReadInt32(); ShaderFlags shaderFlags = (ShaderFlags)ctabReader.ReadInt32(); - Console.WriteLine("Flags = {0}", shaderFlags); + Console.WriteLine("Flags: {0}", shaderFlags); long shaderModelPosition = ctabReader.ReadInt32(); //Console.WriteLine("ctabStart = {0}, shaderModelPosition = {1}", ctabStart, shaderModelPosition); @@ -70,11 +70,11 @@ public IList ParseConstantTable() ctabStream.Position = creatorPosition; string compilerInfo = ReadStringNullTerminated(ctabStream); - Console.WriteLine(compilerInfo); + Console.WriteLine("Compiler: " + compilerInfo); ctabStream.Position = shaderModelPosition; string shaderModel = ReadStringNullTerminated(ctabStream); - Console.WriteLine(shaderModel); + Console.WriteLine("Shader model: " + shaderModel); for (int i = 0; i < numConstants; i++) diff --git a/HlslDecompiler.Tests/ShaderAssembly/ps_dot_product2_add.asm b/HlslDecompiler.Tests/ShaderAssembly/ps_dot_product2_add.asm index 27d17be..34f525d 100644 --- a/HlslDecompiler.Tests/ShaderAssembly/ps_dot_product2_add.asm +++ b/HlslDecompiler.Tests/ShaderAssembly/ps_dot_product2_add.asm @@ -2,4 +2,4 @@ ps_3_0 def c0, 1, 2, 3, 4 dcl_texcoord v0.yzw dp2add oC0.x, v0.y, v0.z, c0.x -mov oC0.yzw, c0.xyz +mov oC0.yzw, c0.yzw diff --git a/HlslDecompiler.Tests/ShaderAssembly/ps_float4_construct2.asm b/HlslDecompiler.Tests/ShaderAssembly/ps_float4_construct2.asm index a8c4378..6e7940e 100644 --- a/HlslDecompiler.Tests/ShaderAssembly/ps_float4_construct2.asm +++ b/HlslDecompiler.Tests/ShaderAssembly/ps_float4_construct2.asm @@ -6,4 +6,4 @@ mad oC0, v0.xxxy, c0.xyyx, c0.yyxy mad oC1, v0.xxxy, c0.yyxx, c0.yxyy mad oC2, v0.x, c0.yyyx, c0.yxzy mov oC3.xy, v0.xy -mov oC3.zw, v1.xy +mov oC3.zw, v1.zw diff --git a/HlslDecompiler.Tests/ShaderAssembly/ps_negate_absolute.asm b/HlslDecompiler.Tests/ShaderAssembly/ps_negate_absolute.asm index ef67ff1..1ab4425 100644 --- a/HlslDecompiler.Tests/ShaderAssembly/ps_negate_absolute.asm +++ b/HlslDecompiler.Tests/ShaderAssembly/ps_negate_absolute.asm @@ -2,4 +2,4 @@ ps_3_0 def c0, 1, 0, 2, 0 dcl_texcoord v0.xz mov oC0.x, -v0.z_abs -mad oC0.yzw, v0.xxx, c0.xxy, c0.xyx +mad oC0.yzw, v0.xxx, c0.xyy, c0.yxz diff --git a/HlslDecompiler.Tests/ShaderAssembly/vs_matrix22_vector2_multiply.asm b/HlslDecompiler.Tests/ShaderAssembly/vs_matrix22_vector2_multiply.asm index a7ec6cc..0410cad 100644 --- a/HlslDecompiler.Tests/ShaderAssembly/vs_matrix22_vector2_multiply.asm +++ b/HlslDecompiler.Tests/ShaderAssembly/vs_matrix22_vector2_multiply.asm @@ -8,5 +8,5 @@ mad o0, c0.xyxy, v0.xxyy, r0 mul r0.xy, c1.xy, v0.xx_abs mad o1.xy, c0.xy, v0.yy_abs, r0.xy add r0.xy, v0.xy, v0.xy -mul r0.yz, r0.yy, c1.xx +mul r0.yz, r0.yy, c1.xy mad o2.xy, c0.xy, r0.xx, r0.yz diff --git a/HlslDecompiler.Tests/ShaderAssembly/vs_vector2_matrix22_multiply.asm b/HlslDecompiler.Tests/ShaderAssembly/vs_vector2_matrix22_multiply.asm index c5ef769..6bff891 100644 --- a/HlslDecompiler.Tests/ShaderAssembly/vs_vector2_matrix22_multiply.asm +++ b/HlslDecompiler.Tests/ShaderAssembly/vs_vector2_matrix22_multiply.asm @@ -4,9 +4,9 @@ dcl_position o0 dcl_position1 o1.xy dcl_position2 o2.xy mul r0, c0.xyxy, v0.xyyx -add o0.xz, r0.yy, r0.xy +add o0.xz, r0.yw, r0.xz mul r0, c1.xyxy, v0.xyyx -add o0.yw, r0.xy, r0.xx +add o0.yw, r0.yw, r0.xz mul r0.xy, c0.xy, v0.yx_abs add o1.x, r0.y, r0.x mul r0.xy, c1.xy, v0.yx_abs diff --git a/HlslDecompiler.csproj b/HlslDecompiler.csproj index dbd320c..69d70e0 100644 --- a/HlslDecompiler.csproj +++ b/HlslDecompiler.csproj @@ -44,6 +44,7 @@ + diff --git a/Program.cs b/Program.cs index 0b36095..79922ac 100644 --- a/Program.cs +++ b/Program.cs @@ -8,28 +8,25 @@ class Program { static void Main(string[] args) { - if (args.Length != 1) + var options = CommandLineOptions.Parse(args); + if (options.InputFilename == null) { Console.WriteLine("Expected input filename"); return; } - string inputFilename = args[0]; - string baseFilename = Path.GetFileNameWithoutExtension(inputFilename); - - // Try to simplify HLSL expressions by doing AST analysis - bool doAstAnalysis = false; + string baseFilename = Path.GetFileNameWithoutExtension(options.InputFilename); - using (var inputStream = File.Open(inputFilename, FileMode.Open, FileAccess.Read)) + using (var inputStream = File.Open(options.InputFilename, FileMode.Open, FileAccess.Read)) { var format = FormatDetector.Detect(inputStream); switch (format) { case ShaderFileFormat.ShaderModel: - ReadShaderModel(baseFilename, inputStream, doAstAnalysis); + ReadShaderModel(baseFilename, inputStream, options.DoAstAnalysis); break; case ShaderFileFormat.Rgxa: - ReadRgxa(baseFilename, inputStream, doAstAnalysis); + ReadRgxa(baseFilename, inputStream, options.DoAstAnalysis); break; case ShaderFileFormat.Unknown: Console.WriteLine("Unknown file format!"); @@ -37,22 +34,24 @@ static void Main(string[] args) } } - Console.ReadKey(); + Console.WriteLine("Finished."); } private static void ReadShaderModel(string baseFilename, FileStream inputStream, bool doAstAnalysis) { using (var input = new ShaderReader(inputStream, true)) { - Console.WriteLine(); - Console.WriteLine("{0}", baseFilename); ShaderModel shader = input.ReadShader(); AsmWriter writer = new AsmWriter(shader); - writer.Write($"{baseFilename}.asm"); + string asmFilename = $"{baseFilename}.asm"; + Console.WriteLine("Writing {0}", asmFilename); + writer.Write(asmFilename); var hlslWriter = CreateHlslWriter(shader, doAstAnalysis); - hlslWriter.Write($"{baseFilename}.fx"); + string hlslFilename = $"{baseFilename}.fx"; + Console.WriteLine("Writing {0}", hlslFilename); + hlslWriter.Write(hlslFilename); } } @@ -89,8 +88,6 @@ private static void ReadRgxa(string baseFilename, FileStream inputStream, bool d var hlslWriter = CreateHlslWriter(shader, doAstAnalysis); hlslWriter.Write(outFilename + ".fx"); - - Console.WriteLine(); } } } diff --git a/README.md b/README.md index e0afe1d..27d3d38 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,35 @@ # HlslDecompiler Decompiles Shader Model 3.0 shaders into HLSL code + +## Usage +`HlslDecompiler [--ast] shader.fxc` + +The program will output the assembly listing in shader.asm, e.g. +``` +ps_3_0 +def c0, 1, 0, 2, 0 +dcl_texcoord v0.xz +mov oC0.x, -v0.z_abs +mad oC0.yzw, v0.xxx, c0.xyy, c0.yxz +``` +and the decompiled HLSL code in shader.fx: +``` +float4 main(float3 texcoord : TEXCOORD) : COLOR +{ + float4 o; + + o.x = -abs(texcoord.z); + o.yzw = texcoord.xxx * float3(1, 0, 0) + float3(0, 1, 2); + + return o; +} +``` + +With the --ast option, the program will attempt generate more readable HLSL. +It does this by taking the shader bytecode, constructing an abstract syntax tree, simplyfying it and compiling to HLSL: +``` +float4 main(float3 texcoord : TEXCOORD) : COLOR +{ + return float4(-abs(texcoord.z), texcoord.x, 1, 2); +} +``` \ No newline at end of file