Initial SPIR-V decompiling support
This commit is contained in:
parent
f1e866e248
commit
2c9cd5e938
6 changed files with 3843 additions and 8 deletions
70
Ryujinx.Graphics/Gal/Shader/SpirvAssembler.cs
Normal file
70
Ryujinx.Graphics/Gal/Shader/SpirvAssembler.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader.SPIRV
|
||||
{
|
||||
public class Assembler
|
||||
{
|
||||
private List<Instruction> Instructions;
|
||||
|
||||
public Assembler()
|
||||
{
|
||||
Instructions = new List<Instruction>();
|
||||
}
|
||||
|
||||
public void Write(Stream Output)
|
||||
{
|
||||
uint Bound = DoBindings();
|
||||
|
||||
var BinaryWriter = new BinaryWriter(Output);
|
||||
|
||||
BinaryWriter.Write((uint)BinaryForm.MagicNumber);
|
||||
BinaryWriter.Write((uint)BinaryForm.VersionNumber);
|
||||
BinaryWriter.Write((uint)BinaryForm.GeneratorMagicNumber);
|
||||
BinaryWriter.Write((uint)Bound);
|
||||
BinaryWriter.Write((uint)0); // Reserved for instruction schema
|
||||
|
||||
foreach (var Instruction in Instructions)
|
||||
{
|
||||
Instruction.Write(BinaryWriter);
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(Instruction Instruction)
|
||||
{
|
||||
Instructions.Add(Instruction);
|
||||
}
|
||||
|
||||
public void Add(Instruction[] Instructions)
|
||||
{
|
||||
foreach (Instruction Instruction in Instructions)
|
||||
{
|
||||
Add(Instruction);
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(List<Instruction> Instructions)
|
||||
{
|
||||
foreach (Instruction Instruction in Instructions)
|
||||
{
|
||||
Add(Instruction);
|
||||
}
|
||||
}
|
||||
|
||||
private uint DoBindings()
|
||||
{
|
||||
uint Bind = 1;
|
||||
|
||||
foreach (var Instruction in Instructions)
|
||||
{
|
||||
if (Instruction.HoldsResultId)
|
||||
{
|
||||
Instruction.ResultId = Bind;
|
||||
Bind++;
|
||||
}
|
||||
}
|
||||
|
||||
return Bind;
|
||||
}
|
||||
}
|
||||
}
|
1121
Ryujinx.Graphics/Gal/Shader/SpirvBinaryForm.cs
Normal file
1121
Ryujinx.Graphics/Gal/Shader/SpirvBinaryForm.cs
Normal file
File diff suppressed because it is too large
Load diff
1146
Ryujinx.Graphics/Gal/Shader/SpirvDecompiler.cs
Normal file
1146
Ryujinx.Graphics/Gal/Shader/SpirvDecompiler.cs
Normal file
File diff suppressed because it is too large
Load diff
1332
Ryujinx.Graphics/Gal/Shader/SpirvInstruction.cs
Normal file
1332
Ryujinx.Graphics/Gal/Shader/SpirvInstruction.cs
Normal file
File diff suppressed because it is too large
Load diff
151
Ryujinx.Graphics/Gal/Shader/SpirvOperand.cs
Normal file
151
Ryujinx.Graphics/Gal/Shader/SpirvOperand.cs
Normal file
|
@ -0,0 +1,151 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader.SPIRV
|
||||
{
|
||||
public abstract class Operand
|
||||
{
|
||||
public abstract int GetWordCount();
|
||||
|
||||
public abstract void Write(BinaryWriter BinaryWriter);
|
||||
}
|
||||
|
||||
public class Id: Operand
|
||||
{
|
||||
private Instruction Instruction;
|
||||
|
||||
public Id(Instruction Instruction)
|
||||
{
|
||||
this.Instruction = Instruction;
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter BinaryWriter)
|
||||
{
|
||||
BinaryWriter.Write((uint)Instruction.ResultId);
|
||||
}
|
||||
|
||||
public override int GetWordCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Literal: Operand
|
||||
{
|
||||
}
|
||||
|
||||
public class LiteralString: Literal
|
||||
{
|
||||
public byte[] Value;
|
||||
|
||||
public LiteralString(string String)
|
||||
{
|
||||
Value = Encoding.UTF8.GetBytes(String);
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter BinaryWriter)
|
||||
{
|
||||
BinaryWriter.Write(Value);
|
||||
|
||||
// Write remaining zero bytes
|
||||
for (int i = 0; i < 4 - (Value.Length % 4); i++)
|
||||
{
|
||||
BinaryWriter.Write((byte)0);
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetWordCount()
|
||||
{
|
||||
return Value.Length / 4 + 1;
|
||||
}
|
||||
|
||||
public override bool Equals(object Object)
|
||||
{
|
||||
if (Object is LiteralString Other)
|
||||
{
|
||||
return this.Value == Other.Value;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class LiteralNumber: Literal
|
||||
{
|
||||
public TypeCode Type;
|
||||
|
||||
public int Integer;
|
||||
|
||||
public float Float32;
|
||||
|
||||
public double Float64;
|
||||
|
||||
public LiteralNumber(int Value)
|
||||
{
|
||||
Integer = Value;
|
||||
Type = Value.GetTypeCode();
|
||||
}
|
||||
|
||||
public LiteralNumber(float Value)
|
||||
{
|
||||
Float32 = Value;
|
||||
Type = Value.GetTypeCode();
|
||||
}
|
||||
|
||||
public LiteralNumber(double Value)
|
||||
{
|
||||
Float64 = Value;
|
||||
Type = Value.GetTypeCode();
|
||||
}
|
||||
|
||||
public override void Write(BinaryWriter BinaryWriter)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case TypeCode.Int32:
|
||||
BinaryWriter.Write(Integer);
|
||||
break;
|
||||
|
||||
case TypeCode.Single:
|
||||
BinaryWriter.Write(Float32);
|
||||
break;
|
||||
|
||||
case TypeCode.Double:
|
||||
BinaryWriter.Write(Float64);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetWordCount()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case TypeCode.Int32:
|
||||
case TypeCode.Single:
|
||||
return 1;
|
||||
|
||||
case TypeCode.Double:
|
||||
return 2;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object Object)
|
||||
{
|
||||
if (Object is LiteralNumber Other && this.Type == Other.Type)
|
||||
{
|
||||
return this.Integer == Other.Integer
|
||||
&& this.Float32 == Other.Float32
|
||||
&& this.Float64 == Other.Float64;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using Ryujinx.Graphics.Gal.Shader;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.ShaderTools
|
||||
{
|
||||
|
@ -9,13 +10,11 @@ namespace Ryujinx.ShaderTools
|
|||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length == 2)
|
||||
if (args.Length == 4)
|
||||
{
|
||||
GlslDecompiler Decompiler = new GlslDecompiler();
|
||||
|
||||
GalShaderType ShaderType = GalShaderType.Vertex;
|
||||
|
||||
switch (args[0].ToLower())
|
||||
switch (args[1].ToLower())
|
||||
{
|
||||
case "v": ShaderType = GalShaderType.Vertex; break;
|
||||
case "tc": ShaderType = GalShaderType.TessControl; break;
|
||||
|
@ -24,18 +23,34 @@ namespace Ryujinx.ShaderTools
|
|||
case "f": ShaderType = GalShaderType.Fragment; break;
|
||||
}
|
||||
|
||||
using (FileStream FS = new FileStream(args[1], FileMode.Open, FileAccess.Read))
|
||||
using (FileStream Output = new FileStream(args[3], FileMode.Create))
|
||||
using (FileStream FS = new FileStream(args[2], FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
Memory Mem = new Memory(FS);
|
||||
|
||||
GlslProgram Program = Decompiler.Decompile(Mem, 0, ShaderType);
|
||||
switch (args[0].ToLower())
|
||||
{
|
||||
case "glsl":
|
||||
GlslDecompiler GlslDecompiler = new GlslDecompiler();
|
||||
|
||||
Console.WriteLine(Program.Code);
|
||||
GlslProgram Program = GlslDecompiler.Decompile(Mem, 0, ShaderType);
|
||||
|
||||
Output.Write(System.Text.Encoding.UTF8.GetBytes(Program.Code));
|
||||
|
||||
break;
|
||||
|
||||
case "spirv":
|
||||
SpirvDecompiler SpirvDecompiler = new SpirvDecompiler();
|
||||
|
||||
Output.Write(SpirvDecompiler.Decompile(Mem, 0, ShaderType));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Usage: Ryujinx.ShaderTools [v|tc|te|g|f] shader.bin");
|
||||
Console.WriteLine("Usage: Ryujinx.ShaderTools [spirv|glsl] [v|tc|te|g|f] shader.bin output.bin");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue