/ src / Ryujinx.ShaderTools / Program.cs
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  }