Initial SPIR-V decompiling support

This commit is contained in:
ReinUsesLisp 2018-06-13 00:25:01 -03:00
parent f1e866e248
commit 2c9cd5e938
6 changed files with 3843 additions and 8 deletions

View 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;
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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;
}
}
}

View file

@ -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");
}
}
}