AndresTraks / HlslDecompiler

Decompiles Shader Model 3.0 shaders into HLSL code (work in progress)
MIT License
60 stars 13 forks source link

Unhandled Exception around Loop #1

Open TBirdSoars opened 3 years ago

TBirdSoars commented 3 years ago

I've been trying to find a way to decompile some shaders from Sonic Adventure 2's PC port, and while this program seems to work for some of its shaders, it appears to crash for one with the following exception:

C:\source\repos\HlslDecompiler\bin\Debug>HlslDecompiler.exe sonicvs.wvu
Writing sonicvs.asm
Loop

Unhandled Exception: System.NotImplementedException: The method or operation is not implemented.
   at HlslDecompiler.DirectXShaderModel.Instruction.GetParamRegisterName(Int32 index) in C:\Source\Repos\HlslDecompiler\DirectXShaderModel\Instruction.cs:line 247
   at HlslDecompiler.DirectXShaderModel.AsmWriter.GetSourceName(Instruction instruction, Int32 srcIndex) in C:\Source\Repos\HlslDecompiler\DirectXShaderModel\AsmWriter.cs:line 90
   at HlslDecompiler.DirectXShaderModel.AsmWriter.WriteInstruction(Instruction instruction) in C:\Source\Repos\HlslDecompiler\DirectXShaderModel\AsmWriter.cs:line 158
   at HlslDecompiler.DirectXShaderModel.AsmWriter.Write(String asmFilename) in C:\Source\Repos\HlslDecompiler\DirectXShaderModel\AsmWriter.cs:line 105
   at HlslDecompiler.Program.ReadShaderModel(String baseFilename, FileStream inputStream, Boolean doAstAnalysis) in C:\Source\Repos\HlslDecompiler\Program.cs:line 49
   at HlslDecompiler.Program.Main(String[] args) in C:\Source\Repos\HlslDecompiler\Program.cs:line 26

The resulting assembly listing file is blank and no shader source file is produced.

I've attached a zip folder with the shader and its proper assembly listing generated by FXC from the Visual Studio 2019 Developer Command Prompt: sonicvs.zip

AndresTraks commented 3 years ago

Loops aren't well supported yet. I've made some changes now so that loops wouldn't crash for your case, but it'll be quite a lot of work before the HLSL output starts to make sense. I can't promise much though, since it's only a hobby project.

TBirdSoars commented 3 years ago

Thanks for the quick response! The exception is gone and the assembly listing is now very close to the expected output.

The only thing I'm noticing now is that in the assembly listing, the Loop Counter Register aL is missing from the arrays in the loop, but at line 60, aL took the place of c24.

The HLSL for the loop is therefore not correct, but almost everything else looks right. The output is attached: sonicvs.zip

AndresTraks commented 3 years ago

Fixed the assembly.

HLSL with the --ast flag is hopeless for now, but without the flag, the for-loops look OK.

Global arrays aren't handled properly and the saturate() instruction isn't supported yet.

TBirdSoars commented 3 years ago

Nice fix. Now I'm noticing that the constant registers are being rounded, which causes issues with the game's textures. As an example:

def c5, 0.300000012, 0.699999988, 0.00999999978, -0.00999999978

becomes

def c5, 0.3, 0.7, 0.01, -0.01

I'm guessing these need to be doubles rather than floats, but looking at the code, it looks like it might be rather difficult to implement. The byte array from GetParamBytes has 4 bytes, which works for BitConverter.ToSingle, but BitConverter.ToDouble requires 8 bytes.

AndresTraks commented 3 years ago

Those are 4 byte / single precision values, but I think some precision is lost in the conversions in BitConverter.ToSingle or ToString(CultureInfo.InvariantCulture).

There's an exact way to print doubles, which looks like it could be converted to singles: https://stackoverflow.com/a/1584328/1778371 I'll try that later.

AndresTraks commented 3 years ago

The floating point precision should be what is expected now.

ToString() had too much rounding, so precision was lost, but the SO solution had too much precision and too many decimal digits to match FXC. I think FXC /dumpbin tries to keep as many decimal digits as necessary for the exact same 4 byte float value to be reproduced when recompiled.

TBirdSoars commented 3 years ago

Thanks for taking the time to work on this!

It looks like the latest commit won't build due to line 25 in HlslAstWriter.cs - InstructionToAstParser() isn't defined, but reverting it back to BytecodeParser() enabled it to build. With that, the floats are correct now, but the texture issues are persisting. I think there is something about the way the register values are handled that is causing that. Take the following example:

In the original assembly listing, there is the following line: lrp r2.yzw, r0.y, r5.xxyz, r3.xxyz

but in this application's output, it appears as: lrp r2.yzw, r0.yyy, r5.xyz, r3.xyz

and this seems to be solely responsible for the texture glitches. It seems like other lines in the output have a similar issue, leading to slight differences in lighting as well. I've attached the original and output assembly listings for comparison.

sonicvs.zip

TBirdSoars commented 2 years ago

Sorry if this is a necropost, but I've recently tried testing this again and recompiling the shader results in an error:

C:\Users\TBird\source\repos\HlslDecompiler\bin\Debug\net6.0>fxc /T vs_3_0 /Fo sonicvs.fxc sonicvs.fx
Microsoft (R) Direct3D Shader Compiler 10.1 (using C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86\D3DCOMPILER_47.dll)
Copyright (C) 2013 Microsoft. All rights reserved.

C:\Users\TBird\source\repos\HlslDecompiler\bin\Debug\net6.0\sonicvs.fx(90,18-31): error X3121: array, matrix, vector, or indexable object type expected in index expression

compilation failed; no code produced

At lines 89 and 90 in sonicvs.fx, we have

for (int i0 = 0; i0 < 4; i0++) {
    r3.w = (r2.z < g_LightMask[i].x) ? 1 : 0;

Shouldn't that [i] on line 90 be [i0]? Looks like i is already declared on line 42:

VS_OUT main(VS_IN i)

Also, using the shader assembly that was produced (using vsa.exe from an old DirectX SDK ) results in the following:

20220812173434_1

This is the texture issue I was referring to in https://github.com/AndresTraks/HlslDecompiler/issues/1#issuecomment-828099089 I've attached the assembly and source files produced.

net6.0.zip