Program.cs
1 using CommandLine; 2 using Ryujinx.Graphics.Shader; 3 using Ryujinx.Graphics.Shader.Translation; 4 using System; 5 using System.IO; 6 using System.Runtime.InteropServices; 7 8 namespace Ryujinx.ShaderTools 9 { 10 class Program 11 { 12 private class GpuAccessor : IGpuAccessor 13 { 14 private const int DefaultArrayLength = 32; 15 16 private readonly byte[] _data; 17 18 private int _texturesCount; 19 private int _imagesCount; 20 21 public GpuAccessor(byte[] data) 22 { 23 _data = data; 24 _texturesCount = 0; 25 _imagesCount = 0; 26 } 27 28 public SetBindingPair CreateConstantBufferBinding(int index) 29 { 30 return new SetBindingPair(0, index + 1); 31 } 32 33 public SetBindingPair CreateImageBinding(int count, bool isBuffer) 34 { 35 int binding = _imagesCount; 36 37 _imagesCount += count; 38 39 return new SetBindingPair(3, binding); 40 } 41 42 public SetBindingPair CreateStorageBufferBinding(int index) 43 { 44 return new SetBindingPair(1, index); 45 } 46 47 public SetBindingPair CreateTextureBinding(int count, bool isBuffer) 48 { 49 int binding = _texturesCount; 50 51 _texturesCount += count; 52 53 return new SetBindingPair(2, binding); 54 } 55 56 public ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize) 57 { 58 return MemoryMarshal.Cast<byte, ulong>(new ReadOnlySpan<byte>(_data)[(int)address..]); 59 } 60 61 public int QuerySamplerArrayLengthFromPool() 62 { 63 return DefaultArrayLength; 64 } 65 66 public int QueryTextureArrayLengthFromBuffer(int slot) 67 { 68 return DefaultArrayLength; 69 } 70 71 public int QueryTextureArrayLengthFromPool() 72 { 73 return DefaultArrayLength; 74 } 75 } 76 77 private class Options 78 { 79 [Option("compute", Required = false, Default = false, HelpText = "Indicate that the shader is a compute shader.")] 80 public bool Compute { get; set; } 81 82 [Option("vertex-as-compute", Required = false, Default = false, HelpText = "Indicate that the shader is a vertex shader and should be converted to compute.")] 83 public bool VertexAsCompute { get; set; } 84 85 [Option("vertex-passthrough", Required = false, Default = false, HelpText = "Indicate that the shader is a vertex passthrough shader for compute output.")] 86 public bool VertexPassthrough { get; set; } 87 88 [Option("target-language", Required = false, Default = TargetLanguage.Glsl, HelpText = "Indicate the target shader language to use.")] 89 public TargetLanguage TargetLanguage { get; set; } 90 91 [Option("target-api", Required = false, Default = TargetApi.OpenGL, HelpText = "Indicate the target graphics api to use.")] 92 public TargetApi TargetApi { get; set; } 93 94 [Value(0, MetaName = "input", HelpText = "Binary Maxwell shader input path.", Required = true)] 95 public string InputPath { get; set; } 96 97 [Value(1, MetaName = "output", HelpText = "Decompiled shader output path.", Required = false)] 98 public string OutputPath { get; set; } 99 } 100 101 static void HandleArguments(Options options) 102 { 103 TranslationFlags flags = TranslationFlags.DebugMode; 104 105 if (options.Compute) 106 { 107 flags |= TranslationFlags.Compute; 108 } 109 110 byte[] data = File.ReadAllBytes(options.InputPath); 111 112 TranslationOptions translationOptions = new(options.TargetLanguage, options.TargetApi, flags); 113 TranslatorContext translatorContext = Translator.CreateContext(0, new GpuAccessor(data), translationOptions); 114 115 ShaderProgram program; 116 117 if (options.VertexPassthrough) 118 { 119 program = translatorContext.GenerateVertexPassthroughForCompute(); 120 } 121 else 122 { 123 program = translatorContext.Translate(options.VertexAsCompute); 124 } 125 126 if (options.OutputPath == null) 127 { 128 if (program.BinaryCode != null) 129 { 130 using Stream outputStream = Console.OpenStandardOutput(); 131 132 outputStream.Write(program.BinaryCode); 133 } 134 else 135 { 136 Console.WriteLine(program.Code); 137 } 138 } 139 else 140 { 141 if (program.BinaryCode != null) 142 { 143 File.WriteAllBytes(options.OutputPath, program.BinaryCode); 144 } 145 else 146 { 147 File.WriteAllText(options.OutputPath, program.Code); 148 } 149 } 150 } 151 152 static void Main(string[] args) 153 { 154 Parser.Default.ParseArguments<Options>(args) 155 .WithParsed(options => HandleArguments(options)) 156 .WithNotParsed(errors => errors.Output()); 157 } 158 } 159 }