diff --git a/Ryujinx.Graphics.Shader/ShaderProgram.cs b/Ryujinx.Graphics.Shader/ShaderProgram.cs index 4a6bfea9fc..dd87b67d49 100644 --- a/Ryujinx.Graphics.Shader/ShaderProgram.cs +++ b/Ryujinx.Graphics.Shader/ShaderProgram.cs @@ -7,11 +7,21 @@ namespace Ryujinx.Graphics.Shader public ShaderStage Stage { get; } public string Code { get; private set; } + public byte[] BinaryCode { get; } - public ShaderProgram(ShaderStage stage, string code) + private ShaderProgram(ShaderStage stage) { Stage = stage; - Code = code; + } + + public ShaderProgram(ShaderStage stage, string code) : this(stage) + { + Code = code; + } + + public ShaderProgram(ShaderStage stage, byte[] binaryCode) : this(stage) + { + BinaryCode = binaryCode; } public void Prepend(string line) diff --git a/Ryujinx.Graphics.Shader/Translation/TargetLanguage.cs b/Ryujinx.Graphics.Shader/Translation/TargetLanguage.cs index db839e949a..8314b223c5 100644 --- a/Ryujinx.Graphics.Shader/Translation/TargetLanguage.cs +++ b/Ryujinx.Graphics.Shader/Translation/TargetLanguage.cs @@ -3,6 +3,7 @@ namespace Ryujinx.Graphics.Shader.Translation public enum TargetLanguage { Glsl, - Spirv + Spirv, + Arb } } diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs index 0f71b59963..685b6a20a4 100644 --- a/Ryujinx.Graphics.Shader/Translation/Translator.cs +++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs @@ -3,6 +3,7 @@ using Ryujinx.Graphics.Shader.Decoders; using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.StructuredIr; using Ryujinx.Graphics.Shader.Translation.Optimizations; +using System; using System.Collections.Generic; using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; @@ -87,7 +88,16 @@ namespace Ryujinx.Graphics.Shader.Translation StructuredProgramInfo sInfo = StructuredProgram.MakeStructuredProgram(funcs, config); - string glslCode = GlslGenerator.Generate(sInfo, config); + ShaderProgram program; + + switch (config.Options.TargetLanguage) + { + case TargetLanguage.Glsl: + program = new ShaderProgram(config.Stage, GlslGenerator.Generate(sInfo, config)); + break; + default: + throw new NotImplementedException(config.Options.TargetLanguage.ToString()); + } shaderProgramInfo = new ShaderProgramInfo( config.GetConstantBufferDescriptors(), @@ -97,7 +107,7 @@ namespace Ryujinx.Graphics.Shader.Translation config.UsedFeatures.HasFlag(FeatureFlags.InstanceId), config.ClipDistancesWritten); - return new ShaderProgram(config.Stage, glslCode); + return program; } private static Block[][] DecodeShader( diff --git a/Ryujinx.ShaderTools/Program.cs b/Ryujinx.ShaderTools/Program.cs index 17c242a912..fba0b3ad88 100644 --- a/Ryujinx.ShaderTools/Program.cs +++ b/Ryujinx.ShaderTools/Program.cs @@ -1,4 +1,5 @@ -using Ryujinx.Graphics.Shader; +using CommandLine; +using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader.Translation; using System; using System.IO; @@ -23,28 +24,70 @@ namespace Ryujinx.ShaderTools } } - static void Main(string[] args) + private class Options { - if (args.Length == 1 || args.Length == 2) + [Option("compute", Required = false, Default = false, HelpText = "Indicate that the shader is a compute shader.")] + public bool Compute { get; set; } + + [Option("target-language", Required = false, Default = TargetLanguage.Glsl, HelpText = "Indicate the target shader language to use.")] + public TargetLanguage TargetLanguage { get; set; } + + [Option("target-api", Required = false, Default = TargetApi.OpenGL, HelpText = "Indicate the target graphics api to use.")] + public TargetApi TargetApi { get; set; } + + [Value(0, MetaName = "input", HelpText = "Binary Maxwell shader input path.", Required = true)] + public string InputPath { get; set; } + + [Value(1, MetaName = "output", HelpText = "Decompiled shader output path.", Required = false)] + public string OutputPath { get; set; } + } + + static void HandleArguments(Options options) + { + TranslationFlags flags = TranslationFlags.DebugMode; + + if (options.Compute) { - TranslationFlags flags = TranslationFlags.DebugMode; + flags |= TranslationFlags.Compute; + } - if (args.Length == 2 && args[0] == "--compute") + byte[] data = File.ReadAllBytes(options.InputPath); + + TranslationOptions translationOptions = new TranslationOptions(options.TargetLanguage, options.TargetApi, flags); + + ShaderProgram program = Translator.CreateContext(0, new GpuAccessor(data), translationOptions).Translate(out _); + + if (options.OutputPath == null) + { + if (program.BinaryCode != null) { - flags |= TranslationFlags.Compute; + using Stream outputStream = Console.OpenStandardOutput(); + + outputStream.Write(program.BinaryCode); + } + else + { + Console.WriteLine(program.Code); } - - byte[] data = File.ReadAllBytes(args[^1]); - - TranslationOptions options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, flags); - string code = Translator.CreateContext(0, new GpuAccessor(data), options).Translate(out _).Code; - - Console.WriteLine(code); } else { - Console.WriteLine("Usage: Ryujinx.ShaderTools [--compute] shader.bin"); + if (program.BinaryCode != null) + { + File.WriteAllBytes(options.OutputPath, program.BinaryCode); + } + else + { + File.WriteAllText(options.OutputPath, program.Code); + } } } + + static void Main(string[] args) + { + Parser.Default.ParseArguments(args) + .WithParsed(options => HandleArguments(options)) + .WithNotParsed(errors => errors.Output()); + } } } \ No newline at end of file diff --git a/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj b/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj index 03872c45c9..e11559d5bb 100644 --- a/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj +++ b/Ryujinx.ShaderTools/Ryujinx.ShaderTools.csproj @@ -11,4 +11,8 @@ + + + +