mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2024-12-28 11:33:06 +00:00
SPIR-V Intermediate Shading Language support
* Enable from Ryujinx.conf * Adapt to use OpenTK.NetStandard * Implement usage of UBOs for GLSL and SPIR-V * Fix a NVidia related issue * Use constant from UniformBinding
This commit is contained in:
parent
69697957e6
commit
cc298c676a
20 changed files with 5454 additions and 154 deletions
|
@ -173,10 +173,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Type = AttribTypes[Attrib.Size] + (Unsigned ? 1 : 0);
|
||||
}
|
||||
|
||||
int Size = AttribElements[Attrib.Size];
|
||||
int Offset = Attrib.Offset;
|
||||
int Location = Attrib.Index + 1;
|
||||
int Size = AttribElements[Attrib.Size];
|
||||
int Offset = Attrib.Offset;
|
||||
|
||||
GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Stride, Offset);
|
||||
GL.VertexAttribPointer(Location, Size, Type, Normalize, Stride, Offset);
|
||||
}
|
||||
|
||||
GL.BindVertexArray(0);
|
||||
|
|
|
@ -9,40 +9,33 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
class OGLShader
|
||||
{
|
||||
private class ShaderStage : IDisposable
|
||||
private enum ShadingLanguage
|
||||
{
|
||||
public int Handle { get; private set; }
|
||||
Unknown,
|
||||
GLSL,
|
||||
SPIRV
|
||||
}
|
||||
|
||||
public bool IsCompiled { get; private set; }
|
||||
private abstract class ShaderStage : IDisposable
|
||||
{
|
||||
public int Handle { get; protected set; }
|
||||
|
||||
public GalShaderType Type { get; private set; }
|
||||
|
||||
public string Code { get; private set; }
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> TextureUsage { get; private set; }
|
||||
public IEnumerable<ShaderDeclInfo> UniformUsage { get; private set; }
|
||||
|
||||
public ShaderStage(
|
||||
GalShaderType Type,
|
||||
string Code,
|
||||
IEnumerable<ShaderDeclInfo> TextureUsage,
|
||||
IEnumerable<ShaderDeclInfo> UniformUsage)
|
||||
{
|
||||
this.Type = Type;
|
||||
this.Code = Code;
|
||||
this.Type = Type;
|
||||
this.TextureUsage = TextureUsage;
|
||||
this.UniformUsage = UniformUsage;
|
||||
}
|
||||
|
||||
public void Compile()
|
||||
{
|
||||
if (Handle == 0)
|
||||
{
|
||||
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
|
||||
|
||||
CompileAndCheck(Handle, Code);
|
||||
}
|
||||
}
|
||||
public abstract void Compile();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
@ -60,6 +53,69 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
private class GlslStage : ShaderStage
|
||||
{
|
||||
public string Code { get; private set; }
|
||||
|
||||
public GlslStage(
|
||||
GalShaderType Type,
|
||||
string Code,
|
||||
IEnumerable<ShaderDeclInfo> TextureUsage,
|
||||
IEnumerable<ShaderDeclInfo> UniformUsage)
|
||||
: base(Type, TextureUsage, UniformUsage)
|
||||
{
|
||||
this.Code = Code;
|
||||
}
|
||||
|
||||
public override void Compile()
|
||||
{
|
||||
if (Handle == 0)
|
||||
{
|
||||
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
|
||||
|
||||
GL.ShaderSource(Handle, Code);
|
||||
GL.CompileShader(Handle);
|
||||
|
||||
CheckCompilation(Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SpirvStage : ShaderStage
|
||||
{
|
||||
public byte[] Bytecode { get; private set; }
|
||||
|
||||
public IDictionary<string, int> Locations { get; private set; }
|
||||
|
||||
public SpirvStage(
|
||||
GalShaderType Type,
|
||||
byte[] Bytecode,
|
||||
IEnumerable<ShaderDeclInfo> TextureUsage,
|
||||
IEnumerable<ShaderDeclInfo> UniformUsage,
|
||||
IDictionary<string, int> Locations)
|
||||
: base(Type, TextureUsage, UniformUsage)
|
||||
{
|
||||
this.Bytecode = Bytecode;
|
||||
this.Locations = Locations;
|
||||
}
|
||||
|
||||
public override void Compile()
|
||||
{
|
||||
if (Handle == 0)
|
||||
{
|
||||
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
|
||||
|
||||
BinaryFormat SpirvFormat = (BinaryFormat)0x9551;
|
||||
|
||||
GL.ShaderBinary(1, new int[]{Handle}, SpirvFormat, Bytecode, Bytecode.Length);
|
||||
|
||||
GL.SpecializeShader(Handle, "main", 0, new int[]{}, new int[]{});
|
||||
|
||||
CheckCompilation(Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct ShaderProgram
|
||||
{
|
||||
public ShaderStage Vertex;
|
||||
|
@ -69,12 +125,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
public ShaderStage Fragment;
|
||||
}
|
||||
|
||||
private const int BuffersPerStage = Shader.UniformBinding.BuffersPerStage;
|
||||
|
||||
private const int BufferSize = 16 * 1024; //ARB_uniform_buffer, 16 KiB
|
||||
|
||||
private ShaderProgram Current;
|
||||
|
||||
private ConcurrentDictionary<long, ShaderStage> Stages;
|
||||
|
||||
private Dictionary<ShaderProgram, int> Programs;
|
||||
|
||||
private ShadingLanguage Language = ShadingLanguage.Unknown;
|
||||
|
||||
private OGLStreamBuffer[][] Buffers;
|
||||
|
||||
public int CurrentProgramHandle { get; private set; }
|
||||
|
||||
public OGLShader()
|
||||
|
@ -82,6 +146,48 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Stages = new ConcurrentDictionary<long, ShaderStage>();
|
||||
|
||||
Programs = new Dictionary<ShaderProgram, int>();
|
||||
|
||||
Buffers = new OGLStreamBuffer[5][]; //one per stage
|
||||
|
||||
for (int Stage = 0; Stage < 5; Stage++)
|
||||
{
|
||||
Buffers[Stage] = new OGLStreamBuffer[BuffersPerStage];
|
||||
}
|
||||
}
|
||||
|
||||
public void Prepare(bool TrySPIRV)
|
||||
{
|
||||
Console.WriteLine(GL.GetInteger(GetPName.MaxUniformBufferBindings));
|
||||
|
||||
for (int Stage = 0; Stage < 5; Stage++)
|
||||
{
|
||||
for (int Cbuf = 0; Cbuf < BuffersPerStage; Cbuf++)
|
||||
{
|
||||
OGLStreamBuffer Buffer = OGLStreamBuffer.Create(BufferTarget.UniformBuffer, BufferSize);
|
||||
|
||||
Buffer.Allocate();
|
||||
|
||||
Buffers[Stage][Cbuf] = Buffer;
|
||||
}
|
||||
}
|
||||
|
||||
if (TrySPIRV)
|
||||
{
|
||||
if (HasSPIRV())
|
||||
{
|
||||
Console.WriteLine("SPIR-V Shading Language");
|
||||
Language = ShadingLanguage.SPIRV;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("GLSL fallback (SPIR-V not available)");
|
||||
Language = ShadingLanguage.GLSL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Language = ShadingLanguage.GLSL;
|
||||
}
|
||||
}
|
||||
|
||||
public void Create(IGalMemory Memory, long Tag, GalShaderType Type)
|
||||
|
@ -91,13 +197,34 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
private ShaderStage ShaderStageFactory(IGalMemory Memory, long Position, GalShaderType Type)
|
||||
{
|
||||
GlslProgram Program = GetGlslProgram(Memory, Position, Type);
|
||||
switch (Language)
|
||||
{
|
||||
case ShadingLanguage.SPIRV:
|
||||
{
|
||||
SpirvProgram Program = GetSpirvProgram(Memory, Position, Type);
|
||||
|
||||
return new ShaderStage(
|
||||
Type,
|
||||
Program.Code,
|
||||
Program.Textures,
|
||||
Program.Uniforms);
|
||||
return new SpirvStage(
|
||||
Type,
|
||||
Program.Bytecode,
|
||||
Program.Textures,
|
||||
Program.Uniforms,
|
||||
Program.Locations);
|
||||
}
|
||||
|
||||
case ShadingLanguage.GLSL:
|
||||
{
|
||||
GlslProgram Program = GetGlslProgram(Memory, Position, Type);
|
||||
|
||||
return new GlslStage(
|
||||
Type,
|
||||
Program.Code,
|
||||
Program.Textures,
|
||||
Program.Uniforms);
|
||||
}
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private GlslProgram GetGlslProgram(IGalMemory Memory, long Position, GalShaderType Type)
|
||||
|
@ -107,6 +234,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
return Decompiler.Decompile(Memory, Position + 0x50, Type);
|
||||
}
|
||||
|
||||
private SpirvProgram GetSpirvProgram(IGalMemory Memory, long Position, GalShaderType Type)
|
||||
{
|
||||
SpirvDecompiler Decompiler = new SpirvDecompiler();
|
||||
|
||||
return Decompiler.Decompile(Memory, Position + 0x50, Type);
|
||||
}
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Tag)
|
||||
{
|
||||
if (Stages.TryGetValue(Tag, out ShaderStage Stage))
|
||||
|
@ -117,6 +251,73 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
return Enumerable.Empty<ShaderDeclInfo>();
|
||||
}
|
||||
|
||||
private int GetUniformLocation(string Name, ShaderStage Stage)
|
||||
{
|
||||
switch (Language)
|
||||
{
|
||||
case ShadingLanguage.SPIRV:
|
||||
{
|
||||
SpirvStage Spirv = (SpirvStage)Stage;
|
||||
|
||||
if (Spirv.Locations.TryGetValue(Name, out int Location))
|
||||
{
|
||||
return Location;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ShadingLanguage.GLSL:
|
||||
{
|
||||
return GL.GetUniformLocation(CurrentProgramHandle, Name);
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
private bool TrySpirvStageLocation(string Name, ShaderStage Stage, out int Location)
|
||||
{
|
||||
if (Stage == null)
|
||||
{
|
||||
Location = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
SpirvStage Spirv = (SpirvStage)Stage;
|
||||
|
||||
return Spirv.Locations.TryGetValue(Name, out Location);
|
||||
}
|
||||
|
||||
private int GetSpirvLocation(string Name)
|
||||
{
|
||||
int Location;
|
||||
|
||||
if (TrySpirvStageLocation(Name, Current.Vertex, out Location)
|
||||
|| TrySpirvStageLocation(Name, Current.TessControl, out Location)
|
||||
|| TrySpirvStageLocation(Name, Current.TessEvaluation, out Location)
|
||||
|| TrySpirvStageLocation(Name, Current.Geometry, out Location)
|
||||
|| TrySpirvStageLocation(Name, Current.Fragment, out Location))
|
||||
{
|
||||
return Location;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
private int GetUniformLocation(string Name)
|
||||
{
|
||||
switch (Language)
|
||||
{
|
||||
case ShadingLanguage.SPIRV:
|
||||
return GetSpirvLocation(Name);
|
||||
|
||||
case ShadingLanguage.GLSL:
|
||||
return GL.GetUniformLocation(CurrentProgramHandle, Name);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public void SetConstBuffer(long Tag, int Cbuf, byte[] Data)
|
||||
{
|
||||
BindProgram();
|
||||
|
@ -125,21 +326,21 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage.Where(x => x.Cbuf == Cbuf))
|
||||
{
|
||||
int Location = GL.GetUniformLocation(CurrentProgramHandle, DeclInfo.Name);
|
||||
|
||||
int Count = Data.Length >> 2;
|
||||
|
||||
//The Index is the index of the last element,
|
||||
//so we can add 1 to get the uniform array size.
|
||||
Count = Math.Min(Count, DeclInfo.Index + 1);
|
||||
|
||||
unsafe
|
||||
if (Cbuf >= BuffersPerStage)
|
||||
{
|
||||
fixed (byte* Ptr = Data)
|
||||
{
|
||||
GL.Uniform1(Location, Count, (float*)Ptr);
|
||||
}
|
||||
string Message = $"Game tried to write constant buffer #{Cbuf} but only 0-#{BuffersPerStage-1} are supported";
|
||||
throw new NotSupportedException(Message);
|
||||
}
|
||||
|
||||
OGLStreamBuffer Buffer = Buffers[(int)Stage.Type][Cbuf];
|
||||
|
||||
int Size = Math.Min(Data.Length, BufferSize);
|
||||
|
||||
byte[] Destiny = Buffer.Map(Size);
|
||||
|
||||
Array.Copy(Data, Destiny, Size);
|
||||
|
||||
Buffer.Unmap(Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +349,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
BindProgram();
|
||||
|
||||
int Location = GL.GetUniformLocation(CurrentProgramHandle, UniformName);
|
||||
int Location = GetUniformLocation(UniformName);
|
||||
|
||||
GL.Uniform1(Location, Value);
|
||||
}
|
||||
|
@ -157,7 +358,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
BindProgram();
|
||||
|
||||
int Location = GL.GetUniformLocation(CurrentProgramHandle, UniformName);
|
||||
int Location = GetUniformLocation(UniformName);
|
||||
|
||||
GL.Uniform2(Location, X, Y);
|
||||
}
|
||||
|
@ -204,11 +405,33 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
CheckProgramLink(Handle);
|
||||
|
||||
if (Language == ShadingLanguage.GLSL)
|
||||
{
|
||||
BindUniformBlocksIfNotNull(Handle, Current.Vertex);
|
||||
BindUniformBlocksIfNotNull(Handle, Current.TessControl);
|
||||
BindUniformBlocksIfNotNull(Handle, Current.TessEvaluation);
|
||||
BindUniformBlocksIfNotNull(Handle, Current.Geometry);
|
||||
BindUniformBlocksIfNotNull(Handle, Current.Fragment);
|
||||
}
|
||||
|
||||
Programs.Add(Current, Handle);
|
||||
}
|
||||
|
||||
GL.UseProgram(Handle);
|
||||
|
||||
//TODO: This could be done once, right?
|
||||
for (int Stage = 0; Stage < 5; Stage++)
|
||||
{
|
||||
for (int Cbuf = 0; Cbuf < BuffersPerStage; Cbuf++)
|
||||
{
|
||||
OGLStreamBuffer Buffer = Buffers[Stage][Cbuf];
|
||||
|
||||
int Binding = Shader.UniformBinding.Get((GalShaderType)Stage, Cbuf);
|
||||
|
||||
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, Binding, Buffer.Handle);
|
||||
}
|
||||
}
|
||||
|
||||
CurrentProgramHandle = Handle;
|
||||
}
|
||||
|
||||
|
@ -222,12 +445,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
public static void CompileAndCheck(int Handle, string Code)
|
||||
private void BindUniformBlocksIfNotNull(int ProgramHandle, ShaderStage Stage)
|
||||
{
|
||||
GL.ShaderSource(Handle, Code);
|
||||
GL.CompileShader(Handle);
|
||||
if (Stage != null)
|
||||
{
|
||||
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage)
|
||||
{
|
||||
int BlockIndex = GL.GetUniformBlockIndex(ProgramHandle, DeclInfo.Name);
|
||||
|
||||
CheckCompilation(Handle);
|
||||
if (BlockIndex < 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
int Binding = Shader.UniformBinding.Get(Stage.Type, DeclInfo.Cbuf);
|
||||
|
||||
GL.UniformBlockBinding(ProgramHandle, BlockIndex, Binding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckCompilation(int Handle)
|
||||
|
@ -253,5 +488,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
throw new ShaderException(GL.GetProgramInfoLog(Handle));
|
||||
}
|
||||
}
|
||||
|
||||
private static bool HasSPIRV()
|
||||
{
|
||||
int ExtensionCount = GL.GetInteger(GetPName.NumExtensions);
|
||||
|
||||
for (int i = 0; i < ExtensionCount; i++)
|
||||
{
|
||||
if (GL.GetString(StringNameIndexed.Extensions, i) == "GL_ARB_gl_spirv")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
125
Ryujinx.Graphics/Gal/OpenGL/OGLStreamBuffer.cs
Normal file
125
Ryujinx.Graphics/Gal/OpenGL/OGLStreamBuffer.cs
Normal file
|
@ -0,0 +1,125 @@
|
|||
using System;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
abstract class OGLStreamBuffer : IDisposable
|
||||
{
|
||||
public int Handle { get; protected set; }
|
||||
|
||||
protected BufferTarget Target;
|
||||
|
||||
protected int Size;
|
||||
|
||||
private bool Mapped = false;
|
||||
|
||||
public OGLStreamBuffer(BufferTarget Target, int MaxSize)
|
||||
{
|
||||
Handle = 0;
|
||||
Mapped = false;
|
||||
|
||||
this.Target = Target;
|
||||
this.Size = MaxSize;
|
||||
}
|
||||
|
||||
public static OGLStreamBuffer Create(BufferTarget Target, int MaxSize)
|
||||
{
|
||||
return new SubDataBuffer(Target, MaxSize);
|
||||
}
|
||||
|
||||
public void Allocate()
|
||||
{
|
||||
if (this.Handle == 0)
|
||||
{
|
||||
GL.CreateBuffers(1, out int Handle);
|
||||
|
||||
this.Handle = Handle;
|
||||
|
||||
InternAllocate();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Map(int Size)
|
||||
{
|
||||
if (Handle == 0 || Mapped || Size > this.Size)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
byte[] Memory = InternMap(Size);
|
||||
|
||||
Mapped = true;
|
||||
|
||||
return Memory;
|
||||
}
|
||||
|
||||
public void Unmap(int UsedSize)
|
||||
{
|
||||
if (Handle == 0 || !Mapped)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
InternUnmap(UsedSize);
|
||||
|
||||
Mapped = false;
|
||||
}
|
||||
|
||||
protected abstract void InternAllocate();
|
||||
|
||||
protected abstract byte[] InternMap(int Size);
|
||||
|
||||
protected abstract void InternUnmap(int UsedSize);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
if (Disposing && Handle != 0)
|
||||
{
|
||||
GL.DeleteBuffer(Handle);
|
||||
|
||||
Handle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SubDataBuffer : OGLStreamBuffer
|
||||
{
|
||||
private byte[] Memory;
|
||||
|
||||
public SubDataBuffer(BufferTarget Target, int MaxSize)
|
||||
: base(Target, MaxSize)
|
||||
{
|
||||
Memory = new byte[MaxSize];
|
||||
}
|
||||
|
||||
protected override void InternAllocate()
|
||||
{
|
||||
GL.BindBuffer(Target, Handle);
|
||||
|
||||
GL.BufferData(Target, Size, IntPtr.Zero, BufferUsageHint.StreamDraw);
|
||||
}
|
||||
|
||||
protected override byte[] InternMap(int Size)
|
||||
{
|
||||
return Memory;
|
||||
}
|
||||
|
||||
protected override void InternUnmap(int UsedSize)
|
||||
{
|
||||
GL.BindBuffer(Target, Handle);
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* MemoryPtr = Memory)
|
||||
{
|
||||
GL.BufferSubData(Target, IntPtr.Zero, UsedSize, (IntPtr)MemoryPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,6 +34,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
ActionsQueue = new ConcurrentQueue<Action>();
|
||||
}
|
||||
|
||||
public void Initialize(bool TrySPIRV = false)
|
||||
{
|
||||
ActionsQueue.Enqueue(() =>
|
||||
{
|
||||
Shader.Prepare(TrySPIRV);
|
||||
});
|
||||
}
|
||||
|
||||
public void QueueAction(Action ActionMthd)
|
||||
{
|
||||
ActionsQueue.Enqueue(ActionMthd);
|
||||
|
|
|
@ -6,19 +6,12 @@ using System.Text;
|
|||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
public class GlslDecompiler
|
||||
public class GlslDecompiler : ShaderDecompiler
|
||||
{
|
||||
private delegate string GetInstExpr(ShaderIrOp Op);
|
||||
|
||||
private Dictionary<ShaderIrInst, GetInstExpr> InstsExpr;
|
||||
|
||||
private enum OperType
|
||||
{
|
||||
Bool,
|
||||
F32,
|
||||
I32
|
||||
}
|
||||
|
||||
private const string IdentationStr = " ";
|
||||
|
||||
private static string[] ElemTypes = new string[] { "float", "vec2", "vec3", "vec4" };
|
||||
|
@ -145,7 +138,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
foreach (ShaderDeclInfo DeclInfo in Decl.Uniforms.Values.OrderBy(DeclKeySelector))
|
||||
{
|
||||
SB.AppendLine($"uniform {GetDecl(DeclInfo)}[{DeclInfo.Index + 1}];");
|
||||
SB.AppendLine($"layout (std140) uniform {DeclInfo.Name} {{");
|
||||
SB.AppendLine($" vec4 {DeclInfo.Name}_data[{DeclInfo.Index / 4 + 1}];");
|
||||
SB.AppendLine($"}};");
|
||||
}
|
||||
|
||||
if (Decl.Uniforms.Count > 0)
|
||||
|
@ -158,7 +153,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
if (Decl.ShaderType == GalShaderType.Fragment)
|
||||
{
|
||||
SB.AppendLine("in vec4 " + GlslDecl.PositionOutAttrName + ";");
|
||||
SB.AppendLine("layout (location = 0) in vec4 " + GlslDecl.PositionOutAttrName + ";");
|
||||
}
|
||||
|
||||
PrintDeclAttributes(Decl.InAttributes.Values, "in");
|
||||
|
@ -168,7 +163,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
if (Decl.ShaderType == GalShaderType.Vertex)
|
||||
{
|
||||
SB.AppendLine("out vec4 " + GlslDecl.PositionOutAttrName + ";");
|
||||
SB.AppendLine("layout (location = 0) out vec4 " + GlslDecl.PositionOutAttrName + ";");
|
||||
}
|
||||
|
||||
PrintDeclAttributes(Decl.OutAttributes.Values, "out");
|
||||
|
@ -182,7 +177,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
if (DeclInfo.Index >= 0)
|
||||
{
|
||||
SB.AppendLine("layout (location = " + DeclInfo.Index + ") " + InOut + " " + GetDecl(DeclInfo) + ";");
|
||||
int Location = DeclInfo.Index + 1;
|
||||
|
||||
SB.AppendLine("layout (location = " + Location + ") " + InOut + " " + GetDecl(DeclInfo) + ";");
|
||||
|
||||
Count++;
|
||||
}
|
||||
|
@ -232,11 +229,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
private int DeclKeySelector(ShaderDeclInfo DeclInfo)
|
||||
{
|
||||
return DeclInfo.Cbuf << 24 | DeclInfo.Index;
|
||||
}
|
||||
|
||||
private string GetDecl(ShaderDeclInfo DeclInfo)
|
||||
{
|
||||
return ElemTypes[DeclInfo.Size - 1] + " " + DeclInfo.Name;
|
||||
|
@ -437,20 +429,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return Tail;
|
||||
}
|
||||
|
||||
private bool IsValidOutOper(ShaderIrNode Node)
|
||||
{
|
||||
if (Node is ShaderIrOperGpr Gpr && Gpr.IsConst)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (Node is ShaderIrOperPred Pred && Pred.IsConst)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private string GetDstOperName(ShaderIrNode Node)
|
||||
{
|
||||
if (Node is ShaderIrOperAbuf Abuf)
|
||||
|
@ -534,11 +512,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
//This may not be aways the case.
|
||||
string Offset = "(floatBitsToInt(" + GetSrcExpr(Cbuf.Offs) + ") >> 2)";
|
||||
|
||||
return DeclInfo.Name + "[" + Cbuf.Pos + " + " + Offset + "]";
|
||||
string Index = "(" + Cbuf.Pos + " + " + Offset + ")";
|
||||
|
||||
return $"{DeclInfo.Name}_data[{Index} / 4][{Index} % 4]";
|
||||
}
|
||||
else
|
||||
{
|
||||
return DeclInfo.Name + "[" + Cbuf.Pos + "]";
|
||||
return $"{DeclInfo.Name}_data[{Cbuf.Pos / 4}][{Cbuf.Pos % 4}]";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -950,65 +930,5 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
return Expr;
|
||||
}
|
||||
|
||||
private static OperType GetDstNodeType(ShaderIrNode Node)
|
||||
{
|
||||
//Special case instructions with the result type different
|
||||
//from the input types (like integer <-> float conversion) here.
|
||||
if (Node is ShaderIrOp Op)
|
||||
{
|
||||
switch (Op.Inst)
|
||||
{
|
||||
case ShaderIrInst.Stof:
|
||||
case ShaderIrInst.Txlf:
|
||||
case ShaderIrInst.Utof:
|
||||
return OperType.F32;
|
||||
|
||||
case ShaderIrInst.Ftos:
|
||||
case ShaderIrInst.Ftou:
|
||||
return OperType.I32;
|
||||
}
|
||||
}
|
||||
|
||||
return GetSrcNodeType(Node);
|
||||
}
|
||||
|
||||
private static OperType GetSrcNodeType(ShaderIrNode Node)
|
||||
{
|
||||
switch (Node)
|
||||
{
|
||||
case ShaderIrOperAbuf Abuf:
|
||||
return Abuf.Offs == GlslDecl.VertexIdAttr ||
|
||||
Abuf.Offs == GlslDecl.InstanceIdAttr
|
||||
? OperType.I32
|
||||
: OperType.F32;
|
||||
|
||||
case ShaderIrOperCbuf Cbuf: return OperType.F32;
|
||||
case ShaderIrOperGpr Gpr: return OperType.F32;
|
||||
case ShaderIrOperImm Imm: return OperType.I32;
|
||||
case ShaderIrOperImmf Immf: return OperType.F32;
|
||||
case ShaderIrOperPred Pred: return OperType.Bool;
|
||||
|
||||
case ShaderIrOp Op:
|
||||
if (Op.Inst > ShaderIrInst.B_Start &&
|
||||
Op.Inst < ShaderIrInst.B_End)
|
||||
{
|
||||
return OperType.Bool;
|
||||
}
|
||||
else if (Op.Inst > ShaderIrInst.F_Start &&
|
||||
Op.Inst < ShaderIrInst.F_End)
|
||||
{
|
||||
return OperType.F32;
|
||||
}
|
||||
else if (Op.Inst > ShaderIrInst.I_Start &&
|
||||
Op.Inst < ShaderIrInst.I_End)
|
||||
{
|
||||
return OperType.I32;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Node));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,21 +2,17 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
public struct GlslProgram
|
||||
public class GlslProgram : ShaderProgram
|
||||
{
|
||||
public string Code { get; private set; }
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> Textures { get; private set; }
|
||||
public IEnumerable<ShaderDeclInfo> Uniforms { get; private set; }
|
||||
|
||||
public GlslProgram(
|
||||
string Code,
|
||||
IEnumerable<ShaderDeclInfo> Textures,
|
||||
IEnumerable<ShaderDeclInfo> Uniforms)
|
||||
: base(Textures, Uniforms)
|
||||
{
|
||||
this.Code = Code;
|
||||
this.Textures = Textures;
|
||||
this.Uniforms = Uniforms;
|
||||
this.Code = Code;
|
||||
}
|
||||
}
|
||||
}
|
70
Ryujinx.Graphics/Gal/Shader/SPIRV/SpirvAssembler.cs
Normal file
70
Ryujinx.Graphics/Gal/Shader/SPIRV/SpirvAssembler.cs
Normal 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();
|
||||
|
||||
BinaryWriter BW = new BinaryWriter(Output);
|
||||
|
||||
BW.Write((uint)BinaryForm.MagicNumber);
|
||||
BW.Write((uint)BinaryForm.VersionNumber);
|
||||
BW.Write((uint)BinaryForm.GeneratorMagicNumber);
|
||||
BW.Write((uint)Bound);
|
||||
BW.Write((uint)0); // Reserved for instruction schema
|
||||
|
||||
foreach (Instruction Instruction in Instructions)
|
||||
{
|
||||
Instruction.Write(BW);
|
||||
}
|
||||
}
|
||||
|
||||
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 (Instruction Instruction in Instructions)
|
||||
{
|
||||
if (Instruction.HoldsResultId)
|
||||
{
|
||||
Instruction.ResultId = Bind;
|
||||
Bind++;
|
||||
}
|
||||
}
|
||||
|
||||
return Bind;
|
||||
}
|
||||
}
|
||||
}
|
1125
Ryujinx.Graphics/Gal/Shader/SPIRV/SpirvBinaryForm.cs
Normal file
1125
Ryujinx.Graphics/Gal/Shader/SPIRV/SpirvBinaryForm.cs
Normal file
File diff suppressed because it is too large
Load diff
1739
Ryujinx.Graphics/Gal/Shader/SPIRV/SpirvInstruction.cs
Normal file
1739
Ryujinx.Graphics/Gal/Shader/SPIRV/SpirvInstruction.cs
Normal file
File diff suppressed because it is too large
Load diff
162
Ryujinx.Graphics/Gal/Shader/SPIRV/SpirvOperand.cs
Normal file
162
Ryujinx.Graphics/Gal/Shader/SPIRV/SpirvOperand.cs
Normal file
|
@ -0,0 +1,162 @@
|
|||
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 override int GetHashCode()
|
||||
{
|
||||
return Value.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Type.GetHashCode() + Integer.GetHashCode()
|
||||
+ Float32.GetHashCode() + Float64.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
28
Ryujinx.Graphics/Gal/Shader/ShaderBinding.cs
Normal file
28
Ryujinx.Graphics/Gal/Shader/ShaderBinding.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
static class UniformBinding
|
||||
{
|
||||
public const int BuffersPerStage = 12; //ARB_uniform_buffer
|
||||
|
||||
public static int Get(GalShaderType Stage, int Cbuf)
|
||||
{
|
||||
return GetStageIndex(Stage) * BuffersPerStage + Cbuf;
|
||||
}
|
||||
|
||||
private static int GetStageIndex(GalShaderType Stage)
|
||||
{
|
||||
switch (Stage)
|
||||
{
|
||||
case GalShaderType.Vertex: return 0;
|
||||
case GalShaderType.Fragment: return 1;
|
||||
case GalShaderType.Geometry: return 2;
|
||||
case GalShaderType.TessControl: return 3;
|
||||
case GalShaderType.TessEvaluation: return 4;
|
||||
}
|
||||
|
||||
throw new ArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
93
Ryujinx.Graphics/Gal/Shader/ShaderDecompiler.cs
Normal file
93
Ryujinx.Graphics/Gal/Shader/ShaderDecompiler.cs
Normal file
|
@ -0,0 +1,93 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
public class ShaderDecompiler
|
||||
{
|
||||
protected enum OperType
|
||||
{
|
||||
Bool,
|
||||
F32,
|
||||
I32
|
||||
}
|
||||
|
||||
protected static bool IsValidOutOper(ShaderIrNode Node)
|
||||
{
|
||||
if (Node is ShaderIrOperGpr Gpr && Gpr.IsConst)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (Node is ShaderIrOperPred Pred && Pred.IsConst)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static OperType GetDstNodeType(ShaderIrNode Node)
|
||||
{
|
||||
//Special case instructions with the result type different
|
||||
//from the input types (like integer <-> float conversion) here.
|
||||
if (Node is ShaderIrOp Op)
|
||||
{
|
||||
switch (Op.Inst)
|
||||
{
|
||||
case ShaderIrInst.Stof:
|
||||
case ShaderIrInst.Txlf:
|
||||
case ShaderIrInst.Utof:
|
||||
return OperType.F32;
|
||||
|
||||
case ShaderIrInst.Ftos:
|
||||
case ShaderIrInst.Ftou:
|
||||
return OperType.I32;
|
||||
}
|
||||
}
|
||||
|
||||
return GetSrcNodeType(Node);
|
||||
}
|
||||
|
||||
protected static OperType GetSrcNodeType(ShaderIrNode Node)
|
||||
{
|
||||
switch (Node)
|
||||
{
|
||||
case ShaderIrOperAbuf Abuf:
|
||||
return Abuf.Offs == GlslDecl.VertexIdAttr ||
|
||||
Abuf.Offs == GlslDecl.InstanceIdAttr
|
||||
? OperType.I32
|
||||
: OperType.F32;
|
||||
|
||||
case ShaderIrOperCbuf Cbuf: return OperType.F32;
|
||||
case ShaderIrOperGpr Gpr: return OperType.F32;
|
||||
case ShaderIrOperImm Imm: return OperType.I32;
|
||||
case ShaderIrOperImmf Immf: return OperType.F32;
|
||||
case ShaderIrOperPred Pred: return OperType.Bool;
|
||||
|
||||
case ShaderIrOp Op:
|
||||
if (Op.Inst > ShaderIrInst.B_Start &&
|
||||
Op.Inst < ShaderIrInst.B_End)
|
||||
{
|
||||
return OperType.Bool;
|
||||
}
|
||||
else if (Op.Inst > ShaderIrInst.F_Start &&
|
||||
Op.Inst < ShaderIrInst.F_End)
|
||||
{
|
||||
return OperType.F32;
|
||||
}
|
||||
else if (Op.Inst > ShaderIrInst.I_Start &&
|
||||
Op.Inst < ShaderIrInst.I_End)
|
||||
{
|
||||
return OperType.I32;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Node));
|
||||
}
|
||||
|
||||
protected static int DeclKeySelector(ShaderDeclInfo DeclInfo)
|
||||
{
|
||||
return DeclInfo.Cbuf << 24 | DeclInfo.Index;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
class ShaderIrNode { }
|
||||
public class ShaderIrNode { }
|
||||
}
|
18
Ryujinx.Graphics/Gal/Shader/ShaderProgram.cs
Normal file
18
Ryujinx.Graphics/Gal/Shader/ShaderProgram.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
public class ShaderProgram
|
||||
{
|
||||
public IEnumerable<ShaderDeclInfo> Textures { get; private set; }
|
||||
public IEnumerable<ShaderDeclInfo> Uniforms { get; private set; }
|
||||
|
||||
public ShaderProgram(
|
||||
IEnumerable<ShaderDeclInfo> Textures,
|
||||
IEnumerable<ShaderDeclInfo> Uniforms)
|
||||
{
|
||||
this.Textures = Textures;
|
||||
this.Uniforms = Uniforms;
|
||||
}
|
||||
}
|
||||
}
|
1709
Ryujinx.Graphics/Gal/Shader/SpirvDecompiler.cs
Normal file
1709
Ryujinx.Graphics/Gal/Shader/SpirvDecompiler.cs
Normal file
File diff suppressed because it is too large
Load diff
22
Ryujinx.Graphics/Gal/Shader/SpirvProgram.cs
Normal file
22
Ryujinx.Graphics/Gal/Shader/SpirvProgram.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.Shader
|
||||
{
|
||||
public class SpirvProgram : ShaderProgram
|
||||
{
|
||||
public byte[] Bytecode { get; private set; }
|
||||
|
||||
public IDictionary<string, int> Locations { get; private set; }
|
||||
|
||||
public SpirvProgram(
|
||||
byte[] Bytecode,
|
||||
IDictionary<string, int> Locations,
|
||||
IEnumerable<ShaderDeclInfo> Textures,
|
||||
IEnumerable<ShaderDeclInfo> Uniforms)
|
||||
: base(Textures, Uniforms)
|
||||
{
|
||||
this.Bytecode = Bytecode;
|
||||
this.Locations = Locations;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,40 @@ 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();
|
||||
|
||||
SpirvProgram Program = SpirvDecompiler.Decompile(Mem, 0, ShaderType);
|
||||
|
||||
Output.Write(Program.Bytecode);
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ namespace Ryujinx
|
|||
{
|
||||
public static JoyCon FakeJoyCon { get; private set; }
|
||||
|
||||
public static bool EnableSPIRV { get; private set; }
|
||||
|
||||
public static void Read(Logger Log)
|
||||
{
|
||||
string IniFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
|
@ -22,6 +24,8 @@ namespace Ryujinx
|
|||
|
||||
AOptimizations.DisableMemoryChecks = !Convert.ToBoolean(Parser.Value("Enable_Memory_Checks"));
|
||||
|
||||
EnableSPIRV = Convert.ToBoolean(Parser.Value("Enable_SPIRV"));
|
||||
|
||||
Log.SetEnable(LogLevel.Debug, Convert.ToBoolean(Parser.Value("Logging_Enable_Debug")));
|
||||
Log.SetEnable(LogLevel.Stub, Convert.ToBoolean(Parser.Value("Logging_Enable_Stub")));
|
||||
Log.SetEnable(LogLevel.Info, Convert.ToBoolean(Parser.Value("Logging_Enable_Info")));
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#Enable cpu memory checks (slow)
|
||||
Enable_Memory_Checks = false
|
||||
|
||||
#Enable SPIR-V shading language (experimental)
|
||||
Enable_SPIRV = false
|
||||
|
||||
#Enable print debug logs
|
||||
Logging_Enable_Debug = false
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ using OpenTK;
|
|||
using OpenTK.Graphics;
|
||||
using OpenTK.Input;
|
||||
using Ryujinx.Graphics.Gal;
|
||||
using Ryujinx.Graphics.Gal.OpenGL;
|
||||
using Ryujinx.HLE;
|
||||
using Ryujinx.HLE.Input;
|
||||
using System;
|
||||
|
@ -42,6 +43,11 @@ namespace Ryujinx
|
|||
{
|
||||
VSync = VSyncMode.On;
|
||||
|
||||
if (Renderer is OpenGLRenderer OGL)
|
||||
{
|
||||
OGL.Initialize(Config.EnableSPIRV);
|
||||
}
|
||||
|
||||
Renderer.SetWindowSize(Width, Height);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue