2023-12-04 13:17:13 +00:00
using CommandLine ;
2021-07-18 11:49:39 +01:00
using Ryujinx.Graphics.Shader ;
2019-12-01 02:53:09 +00:00
using Ryujinx.Graphics.Shader.Translation ;
2018-05-17 19:25:42 +01:00
using System ;
using System.IO ;
2020-05-06 02:02:28 +01:00
using System.Runtime.InteropServices ;
2018-05-17 19:25:42 +01:00
2018-06-11 01:46:42 +01:00
namespace Ryujinx.ShaderTools
2018-05-17 19:25:42 +01:00
{
class Program
{
2020-05-06 02:02:28 +01:00
private class GpuAccessor : IGpuAccessor
{
2024-04-07 22:25:55 +01:00
private const int DefaultArrayLength = 32 ;
2020-05-06 02:02:28 +01:00
private readonly byte [ ] _data ;
2024-04-07 22:25:55 +01:00
private int _texturesCount ;
private int _imagesCount ;
2020-05-06 02:02:28 +01:00
public GpuAccessor ( byte [ ] data )
{
_data = data ;
2024-04-07 22:25:55 +01:00
_texturesCount = 0 ;
_imagesCount = 0 ;
}
public int CreateConstantBufferBinding ( int index )
{
return index + 1 ;
}
public int CreateImageBinding ( int count , bool isBuffer )
{
int binding = _imagesCount ;
_imagesCount + = count ;
return binding ;
}
public int CreateStorageBufferBinding ( int index )
{
return index ;
}
public int CreateTextureBinding ( int count , bool isBuffer )
{
int binding = _texturesCount ;
_texturesCount + = count ;
return binding ;
2020-05-06 02:02:28 +01:00
}
2021-10-12 21:35:31 +01:00
public ReadOnlySpan < ulong > GetCode ( ulong address , int minimumSize )
2020-05-06 02:02:28 +01:00
{
2023-06-25 20:37:33 +01:00
return MemoryMarshal . Cast < byte , ulong > ( new ReadOnlySpan < byte > ( _data ) [ ( int ) address . . ] ) ;
2020-05-06 02:02:28 +01:00
}
2024-04-07 22:25:55 +01:00
public int QueryTextureArrayLengthFromBuffer ( int slot )
{
return DefaultArrayLength ;
}
2020-05-06 02:02:28 +01:00
}
2021-07-18 11:49:39 +01:00
private class Options
2018-05-17 19:25:42 +01:00
{
2021-07-18 11:49:39 +01:00
[Option("compute", Required = false, Default = false, HelpText = "Indicate that the shader is a compute shader.")]
public bool Compute { get ; set ; }
2023-08-30 01:10:34 +01:00
[Option("vertex-as-compute", Required = false, Default = false, HelpText = "Indicate that the shader is a vertex shader and should be converted to compute.")]
public bool VertexAsCompute { get ; set ; }
[Option("vertex-passthrough", Required = false, Default = false, HelpText = "Indicate that the shader is a vertex passthrough shader for compute output.")]
public bool VertexPassthrough { get ; set ; }
2021-07-18 11:49:39 +01:00
[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 )
2018-05-17 19:25:42 +01:00
{
2021-07-18 11:49:39 +01:00
flags | = TranslationFlags . Compute ;
}
2018-05-17 19:25:42 +01:00
2021-07-18 11:49:39 +01:00
byte [ ] data = File . ReadAllBytes ( options . InputPath ) ;
2023-06-25 20:37:33 +01:00
TranslationOptions translationOptions = new ( options . TargetLanguage , options . TargetApi , flags ) ;
2023-08-30 01:10:34 +01:00
TranslatorContext translatorContext = Translator . CreateContext ( 0 , new GpuAccessor ( data ) , translationOptions ) ;
2018-05-17 19:25:42 +01:00
2023-08-30 01:10:34 +01:00
ShaderProgram program ;
if ( options . VertexPassthrough )
{
program = translatorContext . GenerateVertexPassthroughForCompute ( ) ;
}
else
{
program = translatorContext . Translate ( options . VertexAsCompute ) ;
}
New shader translator implementation (#654)
* Start implementing a new shader translator
* Fix shift instructions and a typo
* Small refactoring on StructuredProgram, move RemovePhis method to a separate class
* Initial geometry shader support
* Implement TLD4
* Fix -- There's no negation on FMUL32I
* Add constant folding and algebraic simplification optimizations, nits
* Some leftovers from constant folding
* Avoid cast for constant assignments
* Add a branch elimination pass, and misc small fixes
* Remove redundant branches, add expression propagation and other improvements on the code
* Small leftovers -- add missing break and continue, remove unused properties, other improvements
* Add null check to handle empty block cases on block visitor
* Add HADD2 and HMUL2 half float shader instructions
* Optimize pack/unpack sequences, some fixes related to half float instructions
* Add TXQ, TLD, TLDS and TLD4S shader texture instructions, and some support for bindless textures, some refactoring on codegen
* Fix copy paste mistake that caused RZ to be ignored on the AST instruction
* Add workaround for conditional exit, and fix half float instruction with constant buffer
* Add missing 0.0 source for TLDS.LZ variants
* Simplify the switch for TLDS.LZ
* Texture instructions related fixes
* Implement the HFMA instruction, and some misc. fixes
* Enable constant folding on UnpackHalf2x16 instructions
* Refactor HFMA to use OpCode* for opcode decoding rather than on the helper methods
* Remove the old shader translator
* Remove ShaderDeclInfo and other unused things
* Add dual vertex shader support
* Add ShaderConfig, used to pass shader type and maximum cbuffer size
* Move and rename some instruction enums
* Move texture instructions into a separate file
* Move operand GetExpression and locals management to OperandManager
* Optimize opcode decoding using a simple list and binary search
* Add missing condition for do-while on goto elimination
* Misc. fixes on texture instructions
* Simplify TLDS switch
* Address PR feedback, and a nit
2019-04-18 00:57:08 +01:00
2021-07-18 11:49:39 +01:00
if ( options . OutputPath = = null )
{
if ( program . BinaryCode ! = null )
{
using Stream outputStream = Console . OpenStandardOutput ( ) ;
2018-05-17 19:25:42 +01:00
2021-07-18 11:49:39 +01:00
outputStream . Write ( program . BinaryCode ) ;
}
else
{
Console . WriteLine ( program . Code ) ;
}
2018-05-17 19:25:42 +01:00
}
else
{
2021-07-18 11:49:39 +01:00
if ( program . BinaryCode ! = null )
{
File . WriteAllBytes ( options . OutputPath , program . BinaryCode ) ;
}
else
{
File . WriteAllText ( options . OutputPath , program . Code ) ;
}
2018-05-17 19:25:42 +01:00
}
}
2021-07-18 11:49:39 +01:00
static void Main ( string [ ] args )
{
Parser . Default . ParseArguments < Options > ( args )
2023-04-25 23:51:07 +01:00
. WithParsed ( options = > HandleArguments ( options ) )
. WithNotParsed ( errors = > errors . Output ( ) ) ;
2021-07-18 11:49:39 +01:00
}
2018-05-17 19:25:42 +01:00
}
2023-06-25 20:37:33 +01:00
}