Refactoring OGLRenderer rasterizer, some cleanup on the glsl decompiler
This commit is contained in:
parent
34053fdc15
commit
5222708e37
13 changed files with 666 additions and 581 deletions
15
Ryujinx.Graphics/Gal/GalClearBufferFlags.cs
Normal file
15
Ryujinx.Graphics/Gal/GalClearBufferFlags.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum GalClearBufferFlags
|
||||||
|
{
|
||||||
|
Depth = 1 << 0,
|
||||||
|
Stencil = 1 << 1,
|
||||||
|
ColorRed = 1 << 2,
|
||||||
|
ColorGreen = 1 << 3,
|
||||||
|
ColorBlue = 1 << 4,
|
||||||
|
ColorAlpha = 1 << 5
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,8 +2,6 @@ namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public struct GalVertexAttrib
|
public struct GalVertexAttrib
|
||||||
{
|
{
|
||||||
public int Index { get; private set; }
|
|
||||||
public int Buffer { get; private set; }
|
|
||||||
public bool IsConst { get; private set; }
|
public bool IsConst { get; private set; }
|
||||||
public int Offset { get; private set; }
|
public int Offset { get; private set; }
|
||||||
|
|
||||||
|
@ -13,16 +11,12 @@ namespace Ryujinx.Graphics.Gal
|
||||||
public bool IsBgra { get; private set; }
|
public bool IsBgra { get; private set; }
|
||||||
|
|
||||||
public GalVertexAttrib(
|
public GalVertexAttrib(
|
||||||
int Index,
|
|
||||||
int Buffer,
|
|
||||||
bool IsConst,
|
bool IsConst,
|
||||||
int Offset,
|
int Offset,
|
||||||
GalVertexAttribSize Size,
|
GalVertexAttribSize Size,
|
||||||
GalVertexAttribType Type,
|
GalVertexAttribType Type,
|
||||||
bool IsBgra)
|
bool IsBgra)
|
||||||
{
|
{
|
||||||
this.Index = Index;
|
|
||||||
this.Buffer = Buffer;
|
|
||||||
this.IsConst = IsConst;
|
this.IsConst = IsConst;
|
||||||
this.Offset = Offset;
|
this.Offset = Offset;
|
||||||
this.Size = Size;
|
this.Size = Size;
|
||||||
|
|
|
@ -21,12 +21,17 @@ namespace Ryujinx.Graphics.Gal
|
||||||
float OffsY,
|
float OffsY,
|
||||||
float Rotate);
|
float Rotate);
|
||||||
|
|
||||||
|
//Rasterizer
|
||||||
|
void ClearBuffers(int RtIndex, GalClearBufferFlags Flags);
|
||||||
|
|
||||||
|
void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs);
|
||||||
|
void RenderVertexArray(int VbIndex);
|
||||||
|
|
||||||
//Shader
|
//Shader
|
||||||
void CreateShader(long Tag, byte[] Data, GalShaderType Type);
|
void CreateShader(long Tag, GalShaderType Type, byte[] Data);
|
||||||
void SetShaderCb(long Tag, int Cbuf, byte[] Data);
|
void SetShaderCb(long Tag, int Cbuf, byte[] Data);
|
||||||
void BindShader(long Tag);
|
void BindShader(long Tag);
|
||||||
|
void BindProgram();
|
||||||
void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs);
|
|
||||||
|
|
||||||
void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height);
|
void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height);
|
||||||
|
|
||||||
|
|
|
@ -219,7 +219,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
PixelFormat.Rgba,
|
PixelFormat.Rgba,
|
||||||
PixelType.UnsignedByte,
|
PixelType.UnsignedByte,
|
||||||
Pixels);
|
Pixels);
|
||||||
|
|
||||||
GL.ActiveTexture(TextureUnit.Texture0);
|
GL.ActiveTexture(TextureUnit.Texture0);
|
||||||
|
|
||||||
GL.BindVertexArray(VaoHandle);
|
GL.BindVertexArray(VaoHandle);
|
||||||
|
|
|
@ -1,7 +1,178 @@
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
class OGLRasterizer
|
class OGLRasterizer
|
||||||
{
|
{
|
||||||
|
private static Dictionary<GalVertexAttribSize, int> AttribElements =
|
||||||
|
new Dictionary<GalVertexAttribSize, int>()
|
||||||
|
{
|
||||||
|
{ GalVertexAttribSize._32_32_32_32, 4 },
|
||||||
|
{ GalVertexAttribSize._32_32_32, 3 },
|
||||||
|
{ GalVertexAttribSize._16_16_16_16, 4 },
|
||||||
|
{ GalVertexAttribSize._32_32, 2 },
|
||||||
|
{ GalVertexAttribSize._16_16_16, 3 },
|
||||||
|
{ GalVertexAttribSize._8_8_8_8, 4 },
|
||||||
|
{ GalVertexAttribSize._16_16, 2 },
|
||||||
|
{ GalVertexAttribSize._32, 1 },
|
||||||
|
{ GalVertexAttribSize._8_8_8, 3 },
|
||||||
|
{ GalVertexAttribSize._8_8, 2 },
|
||||||
|
{ GalVertexAttribSize._16, 1 },
|
||||||
|
{ GalVertexAttribSize._8, 1 },
|
||||||
|
{ GalVertexAttribSize._10_10_10_2, 4 },
|
||||||
|
{ GalVertexAttribSize._11_11_10, 3 }
|
||||||
|
};
|
||||||
|
|
||||||
|
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> AttribTypes =
|
||||||
|
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
||||||
|
{
|
||||||
|
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Int },
|
||||||
|
{ GalVertexAttribSize._32_32_32, VertexAttribPointerType.Int },
|
||||||
|
{ GalVertexAttribSize._16_16_16_16, VertexAttribPointerType.Short },
|
||||||
|
{ GalVertexAttribSize._32_32, VertexAttribPointerType.Int },
|
||||||
|
{ GalVertexAttribSize._16_16_16, VertexAttribPointerType.Short },
|
||||||
|
{ GalVertexAttribSize._8_8_8_8, VertexAttribPointerType.Byte },
|
||||||
|
{ GalVertexAttribSize._16_16, VertexAttribPointerType.Short },
|
||||||
|
{ GalVertexAttribSize._32, VertexAttribPointerType.Int },
|
||||||
|
{ GalVertexAttribSize._8_8_8, VertexAttribPointerType.Byte },
|
||||||
|
{ GalVertexAttribSize._8_8, VertexAttribPointerType.Byte },
|
||||||
|
{ GalVertexAttribSize._16, VertexAttribPointerType.Short },
|
||||||
|
{ GalVertexAttribSize._8, VertexAttribPointerType.Byte },
|
||||||
|
{ GalVertexAttribSize._10_10_10_2, VertexAttribPointerType.Int }, //?
|
||||||
|
{ GalVertexAttribSize._11_11_10, VertexAttribPointerType.Int } //?
|
||||||
|
};
|
||||||
|
|
||||||
|
private struct VertexBuffer
|
||||||
|
{
|
||||||
|
public int VaoHandle;
|
||||||
|
public int VboHandle;
|
||||||
|
|
||||||
|
public int PrimCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private VertexBuffer[] VertexBuffers;
|
||||||
|
|
||||||
|
public OGLRasterizer()
|
||||||
|
{
|
||||||
|
VertexBuffers = new VertexBuffer[32];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
|
||||||
|
{
|
||||||
|
ClearBufferMask Mask = 0;
|
||||||
|
|
||||||
|
//OpenGL doesn't support clearing just a single color channel,
|
||||||
|
//so we can't just clear all channels...
|
||||||
|
if (Flags.HasFlag(GalClearBufferFlags.ColorRed) &&
|
||||||
|
Flags.HasFlag(GalClearBufferFlags.ColorGreen) &&
|
||||||
|
Flags.HasFlag(GalClearBufferFlags.ColorBlue) &&
|
||||||
|
Flags.HasFlag(GalClearBufferFlags.ColorAlpha))
|
||||||
|
{
|
||||||
|
Mask = ClearBufferMask.ColorBufferBit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Flags.HasFlag(GalClearBufferFlags.Depth))
|
||||||
|
{
|
||||||
|
Mask |= ClearBufferMask.DepthBufferBit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Flags.HasFlag(GalClearBufferFlags.Stencil))
|
||||||
|
{
|
||||||
|
Mask |= ClearBufferMask.StencilBufferBit;
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.Clear(Mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs)
|
||||||
|
{
|
||||||
|
EnsureVbInitialized(VbIndex);
|
||||||
|
|
||||||
|
VertexBuffers[VbIndex].PrimCount = Buffer.Length / Stride;
|
||||||
|
|
||||||
|
VertexBuffer Vb = VertexBuffers[VbIndex];
|
||||||
|
|
||||||
|
IntPtr Length = new IntPtr(Buffer.Length);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
|
||||||
|
GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
||||||
|
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
|
||||||
|
|
||||||
|
GL.BindVertexArray(Vb.VaoHandle);
|
||||||
|
|
||||||
|
for (int Attr = 0; Attr < 16; Attr++)
|
||||||
|
{
|
||||||
|
GL.DisableVertexAttribArray(Attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int Index = 0; Index < Attribs.Length; Index++)
|
||||||
|
{
|
||||||
|
GalVertexAttrib Attrib = Attribs[Index];
|
||||||
|
|
||||||
|
GL.EnableVertexAttribArray(Index);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
|
||||||
|
|
||||||
|
bool Unsigned =
|
||||||
|
Attrib.Type == GalVertexAttribType.Unorm ||
|
||||||
|
Attrib.Type == GalVertexAttribType.Uint ||
|
||||||
|
Attrib.Type == GalVertexAttribType.Uscaled;
|
||||||
|
|
||||||
|
bool Normalize =
|
||||||
|
Attrib.Type == GalVertexAttribType.Snorm ||
|
||||||
|
Attrib.Type == GalVertexAttribType.Unorm;
|
||||||
|
|
||||||
|
VertexAttribPointerType Type = 0;
|
||||||
|
|
||||||
|
if (Attrib.Type == GalVertexAttribType.Float)
|
||||||
|
{
|
||||||
|
Type = VertexAttribPointerType.Float;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Type = AttribTypes[Attrib.Size] + (Unsigned ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Size = AttribElements[Attrib.Size];
|
||||||
|
int Offset = Attrib.Offset;
|
||||||
|
|
||||||
|
GL.VertexAttribPointer(Index, Size, Type, Normalize, Stride, Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.BindVertexArray(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RenderVertexArray(int VbIndex)
|
||||||
|
{
|
||||||
|
VertexBuffer Vb = VertexBuffers[VbIndex];
|
||||||
|
|
||||||
|
if (Vb.PrimCount == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.BindVertexArray(Vb.VaoHandle);
|
||||||
|
|
||||||
|
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, Vb.PrimCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureVbInitialized(int VbIndex)
|
||||||
|
{
|
||||||
|
VertexBuffer Vb = VertexBuffers[VbIndex];
|
||||||
|
|
||||||
|
if (Vb.VaoHandle == 0)
|
||||||
|
{
|
||||||
|
Vb.VaoHandle = GL.GenVertexArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Vb.VboHandle == 0)
|
||||||
|
{
|
||||||
|
Vb.VboHandle = GL.GenBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexBuffers[VbIndex] = Vb;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,13 +15,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public GalShaderType Type { get; private set; }
|
public GalShaderType Type { get; private set; }
|
||||||
|
|
||||||
public ICollection<ShaderDeclInfo> TextureUsage { get; private set; }
|
public IEnumerable<ShaderDeclInfo> TextureUsage { get; private set; }
|
||||||
public ICollection<ShaderDeclInfo> UniformUsage { get; private set; }
|
public IEnumerable<ShaderDeclInfo> UniformUsage { get; private set; }
|
||||||
|
|
||||||
public ShaderStage(
|
public ShaderStage(
|
||||||
GalShaderType Type,
|
GalShaderType Type,
|
||||||
ICollection<ShaderDeclInfo> TextureUsage,
|
IEnumerable<ShaderDeclInfo> TextureUsage,
|
||||||
ICollection<ShaderDeclInfo> UniformUsage)
|
IEnumerable<ShaderDeclInfo> UniformUsage)
|
||||||
{
|
{
|
||||||
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
|
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
|
||||||
|
|
||||||
|
@ -61,6 +61,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
private Dictionary<ShaderProgram, int> Programs;
|
private Dictionary<ShaderProgram, int> Programs;
|
||||||
|
|
||||||
|
public int CurrentProgramHandle { get; private set; }
|
||||||
|
|
||||||
public OGLShader()
|
public OGLShader()
|
||||||
{
|
{
|
||||||
Stages = new Dictionary<long, ShaderStage>();
|
Stages = new Dictionary<long, ShaderStage>();
|
||||||
|
@ -68,14 +70,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Programs = new Dictionary<ShaderProgram, int>();
|
Programs = new Dictionary<ShaderProgram, int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Create(long Tag, byte[] Data, GalShaderType Type)
|
public void Create(long Tag, GalShaderType Type, byte[] Data)
|
||||||
{
|
{
|
||||||
if (!Stages.ContainsKey(Tag))
|
if (!Stages.ContainsKey(Tag))
|
||||||
{
|
{
|
||||||
GlslProgram Program = GetGlslProgram(Data, Type);
|
GlslProgram Program = GetGlslProgram(Data, Type);
|
||||||
|
|
||||||
System.Console.WriteLine(Program.Code);
|
|
||||||
|
|
||||||
ShaderStage Stage = new ShaderStage(
|
ShaderStage Stage = new ShaderStage(
|
||||||
Type,
|
Type,
|
||||||
Program.Textures,
|
Program.Textures,
|
||||||
|
@ -94,6 +94,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage.Where(x => x.Cbuf == Cbuf))
|
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage.Where(x => x.Cbuf == Cbuf))
|
||||||
{
|
{
|
||||||
float Value = BitConverter.ToSingle(Data, DeclInfo.Index * 4);
|
float Value = BitConverter.ToSingle(Data, DeclInfo.Index * 4);
|
||||||
|
|
||||||
|
int Location = GL.GetUniformLocation(CurrentProgramHandle, DeclInfo.Name);
|
||||||
|
|
||||||
|
GL.Uniform1(Location, Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,21 +117,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool BindCurrentProgram()
|
public void BindProgram()
|
||||||
{
|
{
|
||||||
if (Current.Vertex == null ||
|
if (Current.Vertex == null ||
|
||||||
Current.Fragment == null)
|
Current.Fragment == null)
|
||||||
{
|
{
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.UseProgram(GetCurrentProgramHandle());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetCurrentProgramHandle()
|
|
||||||
{
|
|
||||||
if (!Programs.TryGetValue(Current, out int Handle))
|
if (!Programs.TryGetValue(Current, out int Handle))
|
||||||
{
|
{
|
||||||
Handle = GL.CreateProgram();
|
Handle = GL.CreateProgram();
|
||||||
|
@ -145,7 +142,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Programs.Add(Current, Handle);
|
Programs.Add(Current, Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Handle;
|
GL.UseProgram(Handle);
|
||||||
|
|
||||||
|
CurrentProgramHandle = Handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AttachIfNotNull(int ProgramHandle, ShaderStage Stage)
|
private void AttachIfNotNull(int ProgramHandle, ShaderStage Stage)
|
||||||
|
|
|
@ -2,29 +2,20 @@ using OpenTK;
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
public class OpenGLRenderer : IGalRenderer
|
public class OpenGLRenderer : IGalRenderer
|
||||||
{
|
{
|
||||||
private struct VertexBuffer
|
|
||||||
{
|
|
||||||
public int VaoHandle;
|
|
||||||
public int VboHandle;
|
|
||||||
|
|
||||||
public int PrimCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct Texture
|
private struct Texture
|
||||||
{
|
{
|
||||||
public int Handle;
|
public int Handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<VertexBuffer> VertexBuffers;
|
|
||||||
|
|
||||||
private Texture[] Textures;
|
private Texture[] Textures;
|
||||||
|
|
||||||
|
private OGLRasterizer Rasterizer;
|
||||||
|
|
||||||
private OGLShader Shader;
|
private OGLShader Shader;
|
||||||
|
|
||||||
private ConcurrentQueue<Action> ActionsQueue;
|
private ConcurrentQueue<Action> ActionsQueue;
|
||||||
|
@ -33,10 +24,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public OpenGLRenderer()
|
public OpenGLRenderer()
|
||||||
{
|
{
|
||||||
VertexBuffers = new List<VertexBuffer>();
|
|
||||||
|
|
||||||
Textures = new Texture[8];
|
Textures = new Texture[8];
|
||||||
|
|
||||||
|
Rasterizer = new OGLRasterizer();
|
||||||
|
|
||||||
Shader = new OGLShader();
|
Shader = new OGLShader();
|
||||||
|
|
||||||
ActionsQueue = new ConcurrentQueue<Action>();
|
ActionsQueue = new ConcurrentQueue<Action>();
|
||||||
|
@ -70,18 +61,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
public void Render()
|
public void Render()
|
||||||
{
|
{
|
||||||
FbRenderer.Render();
|
FbRenderer.Render();
|
||||||
|
|
||||||
for (int Index = 0; Index < VertexBuffers.Count; Index++)
|
|
||||||
{
|
|
||||||
VertexBuffer Vb = VertexBuffers[Index];
|
|
||||||
|
|
||||||
if (Vb.VaoHandle != 0 &&
|
|
||||||
Vb.PrimCount != 0)
|
|
||||||
{
|
|
||||||
GL.BindVertexArray(Vb.VaoHandle);
|
|
||||||
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, Vb.PrimCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetWindowSize(int Width, int Height)
|
public void SetWindowSize(int Width, int Height)
|
||||||
|
@ -110,157 +89,31 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
FbRenderer.Set(Fb, Width, Height, Transform, Offs);
|
FbRenderer.Set(Fb, Width, Height, Transform, Offs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs)
|
public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
|
||||||
{
|
{
|
||||||
if (Index < 0)
|
ActionsQueue.Enqueue(() => Rasterizer.ClearBuffers(RtIndex, Flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs)
|
||||||
|
{
|
||||||
|
if ((uint)VbIndex > 31)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(Index));
|
throw new ArgumentOutOfRangeException(nameof(VbIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Buffer.Length == 0 || Stride == 0)
|
ActionsQueue.Enqueue(() => Rasterizer.SetVertexArray(VbIndex, Stride,
|
||||||
|
Buffer ?? throw new ArgumentNullException(nameof(Buffer)),
|
||||||
|
Attribs ?? throw new ArgumentNullException(nameof(Attribs))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RenderVertexArray(int VbIndex)
|
||||||
|
{
|
||||||
|
if ((uint)VbIndex > 31)
|
||||||
{
|
{
|
||||||
return;
|
throw new ArgumentOutOfRangeException(nameof(VbIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
EnsureVbInitialized(Index);
|
ActionsQueue.Enqueue(() => Rasterizer.RenderVertexArray(VbIndex));
|
||||||
|
|
||||||
VertexBuffer Vb = VertexBuffers[Index];
|
|
||||||
|
|
||||||
Vb.PrimCount = Buffer.Length / Stride;
|
|
||||||
|
|
||||||
VertexBuffers[Index] = Vb;
|
|
||||||
|
|
||||||
IntPtr Length = new IntPtr(Buffer.Length);
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
|
|
||||||
GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
|
|
||||||
|
|
||||||
GL.BindVertexArray(Vb.VaoHandle);
|
|
||||||
|
|
||||||
for (int Attr = 0; Attr < 16; Attr++)
|
|
||||||
{
|
|
||||||
GL.DisableVertexAttribArray(Attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (GalVertexAttrib Attrib in Attribs)
|
|
||||||
{
|
|
||||||
if (Attrib.Index >= 3) break;
|
|
||||||
|
|
||||||
GL.EnableVertexAttribArray(Attrib.Index);
|
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
|
|
||||||
|
|
||||||
int Size = 0;
|
|
||||||
|
|
||||||
switch (Attrib.Size)
|
|
||||||
{
|
|
||||||
case GalVertexAttribSize._8:
|
|
||||||
case GalVertexAttribSize._16:
|
|
||||||
case GalVertexAttribSize._32:
|
|
||||||
Size = 1;
|
|
||||||
break;
|
|
||||||
case GalVertexAttribSize._8_8:
|
|
||||||
case GalVertexAttribSize._16_16:
|
|
||||||
case GalVertexAttribSize._32_32:
|
|
||||||
Size = 2;
|
|
||||||
break;
|
|
||||||
case GalVertexAttribSize._8_8_8:
|
|
||||||
case GalVertexAttribSize._11_11_10:
|
|
||||||
case GalVertexAttribSize._16_16_16:
|
|
||||||
case GalVertexAttribSize._32_32_32:
|
|
||||||
Size = 3;
|
|
||||||
break;
|
|
||||||
case GalVertexAttribSize._8_8_8_8:
|
|
||||||
case GalVertexAttribSize._10_10_10_2:
|
|
||||||
case GalVertexAttribSize._16_16_16_16:
|
|
||||||
case GalVertexAttribSize._32_32_32_32:
|
|
||||||
Size = 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Signed =
|
|
||||||
Attrib.Type == GalVertexAttribType.Snorm ||
|
|
||||||
Attrib.Type == GalVertexAttribType.Sint ||
|
|
||||||
Attrib.Type == GalVertexAttribType.Sscaled;
|
|
||||||
|
|
||||||
bool Normalize =
|
|
||||||
Attrib.Type == GalVertexAttribType.Snorm ||
|
|
||||||
Attrib.Type == GalVertexAttribType.Unorm;
|
|
||||||
|
|
||||||
VertexAttribPointerType Type = 0;
|
|
||||||
|
|
||||||
switch (Attrib.Type)
|
|
||||||
{
|
|
||||||
case GalVertexAttribType.Snorm:
|
|
||||||
case GalVertexAttribType.Unorm:
|
|
||||||
case GalVertexAttribType.Sint:
|
|
||||||
case GalVertexAttribType.Uint:
|
|
||||||
case GalVertexAttribType.Uscaled:
|
|
||||||
case GalVertexAttribType.Sscaled:
|
|
||||||
{
|
|
||||||
switch (Attrib.Size)
|
|
||||||
{
|
|
||||||
case GalVertexAttribSize._8:
|
|
||||||
case GalVertexAttribSize._8_8:
|
|
||||||
case GalVertexAttribSize._8_8_8:
|
|
||||||
case GalVertexAttribSize._8_8_8_8:
|
|
||||||
{
|
|
||||||
Type = Signed
|
|
||||||
? VertexAttribPointerType.Byte
|
|
||||||
: VertexAttribPointerType.UnsignedByte;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case GalVertexAttribSize._16:
|
|
||||||
case GalVertexAttribSize._16_16:
|
|
||||||
case GalVertexAttribSize._16_16_16:
|
|
||||||
case GalVertexAttribSize._16_16_16_16:
|
|
||||||
{
|
|
||||||
Type = Signed
|
|
||||||
? VertexAttribPointerType.Short
|
|
||||||
: VertexAttribPointerType.UnsignedShort;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case GalVertexAttribSize._10_10_10_2:
|
|
||||||
case GalVertexAttribSize._11_11_10:
|
|
||||||
case GalVertexAttribSize._32:
|
|
||||||
case GalVertexAttribSize._32_32:
|
|
||||||
case GalVertexAttribSize._32_32_32:
|
|
||||||
case GalVertexAttribSize._32_32_32_32:
|
|
||||||
{
|
|
||||||
Type = Signed
|
|
||||||
? VertexAttribPointerType.Int
|
|
||||||
: VertexAttribPointerType.UnsignedInt;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case GalVertexAttribType.Float:
|
|
||||||
{
|
|
||||||
Type = VertexAttribPointerType.Float;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.VertexAttribPointer(
|
|
||||||
Attrib.Index,
|
|
||||||
Size,
|
|
||||||
Type,
|
|
||||||
Normalize,
|
|
||||||
Stride,
|
|
||||||
Attrib.Offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.BindVertexArray(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height)
|
public void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height)
|
||||||
|
@ -290,14 +143,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle);
|
GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateShader(long Tag, byte[] Data, GalShaderType Type)
|
public void CreateShader(long Tag, GalShaderType Type, byte[] Data)
|
||||||
{
|
{
|
||||||
if (Data == null)
|
if (Data == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(Data));
|
throw new ArgumentNullException(nameof(Data));
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionsQueue.Enqueue(() => Shader.Create(Tag, Data, Type));
|
ActionsQueue.Enqueue(() => Shader.Create(Tag, Type, Data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetShaderCb(long Tag, int Cbuf, byte[] Data)
|
public void SetShaderCb(long Tag, int Cbuf, byte[] Data)
|
||||||
|
@ -315,26 +168,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
ActionsQueue.Enqueue(() => Shader.Bind(Tag));
|
ActionsQueue.Enqueue(() => Shader.Bind(Tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnsureVbInitialized(int VbIndex)
|
public void BindProgram()
|
||||||
{
|
{
|
||||||
while (VbIndex >= VertexBuffers.Count)
|
ActionsQueue.Enqueue(() => Shader.BindProgram());
|
||||||
{
|
|
||||||
VertexBuffers.Add(new VertexBuffer());
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexBuffer Vb = VertexBuffers[VbIndex];
|
|
||||||
|
|
||||||
if (Vb.VaoHandle == 0)
|
|
||||||
{
|
|
||||||
Vb.VaoHandle = GL.GenVertexArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Vb.VboHandle == 0)
|
|
||||||
{
|
|
||||||
Vb.VboHandle = GL.GenBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexBuffers[VbIndex] = Vb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnsureTexInitialized(int TexIndex)
|
private void EnsureTexInitialized(int TexIndex)
|
||||||
|
|
203
Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
Normal file
203
Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
{
|
||||||
|
class GlslDecl
|
||||||
|
{
|
||||||
|
private const int AttrStartIndex = 8;
|
||||||
|
private const int TexStartIndex = 8;
|
||||||
|
|
||||||
|
private const string InAttrName = "in_attr";
|
||||||
|
private const string OutAttrName = "out_attr";
|
||||||
|
private const string UniformName = "c";
|
||||||
|
|
||||||
|
private const string GprName = "gpr";
|
||||||
|
private const string PredName = "pred";
|
||||||
|
private const string TextureName = "tex";
|
||||||
|
|
||||||
|
public const string FragmentOutputName = "FragColor";
|
||||||
|
|
||||||
|
private string[] StagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" };
|
||||||
|
|
||||||
|
private string StagePrefix;
|
||||||
|
|
||||||
|
private Dictionary<int, ShaderDeclInfo> m_Textures;
|
||||||
|
|
||||||
|
private Dictionary<(int, int), ShaderDeclInfo> m_Uniforms;
|
||||||
|
|
||||||
|
private Dictionary<int, ShaderDeclInfo> m_InAttributes;
|
||||||
|
private Dictionary<int, ShaderDeclInfo> m_OutAttributes;
|
||||||
|
|
||||||
|
private Dictionary<int, ShaderDeclInfo> m_Gprs;
|
||||||
|
private Dictionary<int, ShaderDeclInfo> m_Preds;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<int, ShaderDeclInfo> Textures => m_Textures;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<(int, int), ShaderDeclInfo> Uniforms => m_Uniforms;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<int, ShaderDeclInfo> InAttributes => m_InAttributes;
|
||||||
|
public IReadOnlyDictionary<int, ShaderDeclInfo> OutAttributes => m_OutAttributes;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<int, ShaderDeclInfo> Gprs => m_Gprs;
|
||||||
|
public IReadOnlyDictionary<int, ShaderDeclInfo> Preds => m_Preds;
|
||||||
|
|
||||||
|
public GalShaderType ShaderType { get; private set; }
|
||||||
|
|
||||||
|
public GlslDecl(ShaderIrNode[] Nodes, GalShaderType ShaderType)
|
||||||
|
{
|
||||||
|
this.ShaderType = ShaderType;
|
||||||
|
|
||||||
|
StagePrefix = StagePrefixes[(int)ShaderType] + "_";
|
||||||
|
|
||||||
|
m_Uniforms = new Dictionary<(int, int), ShaderDeclInfo>();
|
||||||
|
|
||||||
|
m_Textures = new Dictionary<int, ShaderDeclInfo>();
|
||||||
|
|
||||||
|
m_InAttributes = new Dictionary<int, ShaderDeclInfo>();
|
||||||
|
m_OutAttributes = new Dictionary<int, ShaderDeclInfo>();
|
||||||
|
|
||||||
|
m_Gprs = new Dictionary<int, ShaderDeclInfo>();
|
||||||
|
m_Preds = new Dictionary<int, ShaderDeclInfo>();
|
||||||
|
|
||||||
|
//FIXME: Only valid for vertex shaders.
|
||||||
|
if (ShaderType == GalShaderType.Fragment)
|
||||||
|
{
|
||||||
|
m_Gprs.Add(0, new ShaderDeclInfo(FragmentOutputName, 0, 0, 4));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_OutAttributes.Add(7, new ShaderDeclInfo("gl_Position", -1, 0, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ShaderIrNode Node in Nodes)
|
||||||
|
{
|
||||||
|
Traverse(null, Node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Traverse(ShaderIrNode Parent, ShaderIrNode Node)
|
||||||
|
{
|
||||||
|
switch (Node)
|
||||||
|
{
|
||||||
|
case ShaderIrAsg Asg:
|
||||||
|
{
|
||||||
|
Traverse(Asg, Asg.Dst);
|
||||||
|
Traverse(Asg, Asg.Src);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ShaderIrCond Cond:
|
||||||
|
{
|
||||||
|
Traverse(Cond, Cond.Pred);
|
||||||
|
Traverse(Cond, Cond.Child);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ShaderIrOp Op:
|
||||||
|
{
|
||||||
|
Traverse(Op, Op.OperandA);
|
||||||
|
Traverse(Op, Op.OperandB);
|
||||||
|
Traverse(Op, Op.OperandC);
|
||||||
|
|
||||||
|
if (Op.Inst == ShaderIrInst.Texr ||
|
||||||
|
Op.Inst == ShaderIrInst.Texg ||
|
||||||
|
Op.Inst == ShaderIrInst.Texb ||
|
||||||
|
Op.Inst == ShaderIrInst.Texa)
|
||||||
|
{
|
||||||
|
int Handle = ((ShaderIrOperImm)Op.OperandC).Imm;
|
||||||
|
|
||||||
|
int Index = Handle - TexStartIndex;
|
||||||
|
|
||||||
|
string Name = StagePrefix + TextureName + Index;
|
||||||
|
|
||||||
|
m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Index));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ShaderIrOperCbuf Cbuf:
|
||||||
|
{
|
||||||
|
string Name = StagePrefix + UniformName + Cbuf.Index + "_" + Cbuf.Offs;
|
||||||
|
|
||||||
|
ShaderDeclInfo DeclInfo = new ShaderDeclInfo(Name, Cbuf.Offs, Cbuf.Index);
|
||||||
|
|
||||||
|
m_Uniforms.TryAdd((Cbuf.Index, Cbuf.Offs), DeclInfo);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ShaderIrOperAbuf Abuf:
|
||||||
|
{
|
||||||
|
int Index = Abuf.Offs >> 4;
|
||||||
|
int Elem = (Abuf.Offs >> 2) & 3;
|
||||||
|
|
||||||
|
int GlslIndex = Index - AttrStartIndex;
|
||||||
|
|
||||||
|
ShaderDeclInfo DeclInfo;
|
||||||
|
|
||||||
|
if (Parent is ShaderIrAsg Asg && Asg.Dst == Node)
|
||||||
|
{
|
||||||
|
if (!m_OutAttributes.TryGetValue(Index, out DeclInfo))
|
||||||
|
{
|
||||||
|
DeclInfo = new ShaderDeclInfo(OutAttrName + GlslIndex, GlslIndex);
|
||||||
|
|
||||||
|
m_OutAttributes.Add(Index, DeclInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!m_InAttributes.TryGetValue(Index, out DeclInfo))
|
||||||
|
{
|
||||||
|
DeclInfo = new ShaderDeclInfo(InAttrName + GlslIndex, GlslIndex);
|
||||||
|
|
||||||
|
m_InAttributes.Add(Index, DeclInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeclInfo.Enlarge(Elem + 1);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ShaderIrOperGpr Gpr:
|
||||||
|
{
|
||||||
|
if (!Gpr.IsConst && !HasName(m_Gprs, Gpr.Index))
|
||||||
|
{
|
||||||
|
string Name = GprName + Gpr.Index;
|
||||||
|
|
||||||
|
m_Gprs.TryAdd(Gpr.Index, new ShaderDeclInfo(Name, Gpr.Index));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ShaderIrOperPred Pred:
|
||||||
|
{
|
||||||
|
if (!Pred.IsConst && !HasName(m_Preds, Pred.Index))
|
||||||
|
{
|
||||||
|
string Name = PredName + Pred.Index;
|
||||||
|
|
||||||
|
m_Preds.TryAdd(Pred.Index, new ShaderDeclInfo(Name, Pred.Index));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool HasName(Dictionary<int, ShaderDeclInfo> Decls, int Index)
|
||||||
|
{
|
||||||
|
int VecIndex = Index >> 2;
|
||||||
|
|
||||||
|
if (Decls.TryGetValue(VecIndex, out ShaderDeclInfo DeclInfo))
|
||||||
|
{
|
||||||
|
if (DeclInfo.Size > 1 && Index < VecIndex + DeclInfo.Size)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Decls.ContainsKey(Index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,26 +16,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private static string[] ElemTypes = new string[] { "float", "vec2", "vec3", "vec4" };
|
private static string[] ElemTypes = new string[] { "float", "vec2", "vec3", "vec4" };
|
||||||
|
|
||||||
private Dictionary<int, ShaderDeclInfo> Textures;
|
private GlslDecl Decl;
|
||||||
|
|
||||||
private Dictionary<(int, int), ShaderDeclInfo> Uniforms;
|
|
||||||
|
|
||||||
private Dictionary<int, ShaderDeclInfo> InAttributes;
|
|
||||||
private Dictionary<int, ShaderDeclInfo> OutAttributes;
|
|
||||||
|
|
||||||
private Dictionary<int, ShaderDeclInfo> Gprs;
|
|
||||||
private Dictionary<int, ShaderDeclInfo> Preds;
|
|
||||||
|
|
||||||
private const int AttrStartIndex = 8;
|
|
||||||
private const int TexStartIndex = 8;
|
|
||||||
|
|
||||||
private const string InputAttrName = "in_attr";
|
|
||||||
private const string OutputName = "out_attr";
|
|
||||||
private const string UniformName = "c";
|
|
||||||
|
|
||||||
private const string GprName = "gpr";
|
|
||||||
private const string PredName = "pred";
|
|
||||||
private const string TextureName = "tex";
|
|
||||||
|
|
||||||
private StringBuilder SB;
|
private StringBuilder SB;
|
||||||
|
|
||||||
|
@ -72,38 +53,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlslProgram Decompile(int[] Code, GalShaderType Type)
|
public GlslProgram Decompile(int[] Code, GalShaderType ShaderType)
|
||||||
{
|
{
|
||||||
Uniforms = new Dictionary<(int, int), ShaderDeclInfo>();
|
ShaderIrBlock Block = ShaderDecoder.DecodeBasicBlock(Code, 0, ShaderType);
|
||||||
|
|
||||||
Textures = new Dictionary<int, ShaderDeclInfo>();
|
|
||||||
|
|
||||||
InAttributes = new Dictionary<int, ShaderDeclInfo>();
|
|
||||||
OutAttributes = new Dictionary<int, ShaderDeclInfo>();
|
|
||||||
|
|
||||||
Gprs = new Dictionary<int, ShaderDeclInfo>();
|
|
||||||
Preds = new Dictionary<int, ShaderDeclInfo>();
|
|
||||||
|
|
||||||
SB = new StringBuilder();
|
|
||||||
|
|
||||||
//FIXME: Only valid for vertex shaders.
|
|
||||||
if (Type == GalShaderType.Fragment)
|
|
||||||
{
|
|
||||||
Gprs.Add(0, new ShaderDeclInfo("FragColor", 0, 0, 4));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
OutAttributes.Add(7, new ShaderDeclInfo("gl_Position", -1, 0, 4));
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderIrBlock Block = ShaderDecoder.DecodeBasicBlock(Code, 0, Type);
|
|
||||||
|
|
||||||
ShaderIrNode[] Nodes = Block.GetNodes();
|
ShaderIrNode[] Nodes = Block.GetNodes();
|
||||||
|
|
||||||
foreach (ShaderIrNode Node in Nodes)
|
Decl = new GlslDecl(Nodes, ShaderType);
|
||||||
{
|
|
||||||
Traverse(null, Node);
|
SB = new StringBuilder();
|
||||||
}
|
|
||||||
|
|
||||||
SB.AppendLine("#version 430");
|
SB.AppendLine("#version 430");
|
||||||
|
|
||||||
|
@ -120,133 +78,23 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
return new GlslProgram(
|
return new GlslProgram(
|
||||||
GlslCode,
|
GlslCode,
|
||||||
Textures.Values,
|
Decl.Textures.Values,
|
||||||
Uniforms.Values);
|
Decl.Uniforms.Values);
|
||||||
}
|
|
||||||
|
|
||||||
private void Traverse(ShaderIrNode Parent, ShaderIrNode Node)
|
|
||||||
{
|
|
||||||
switch (Node)
|
|
||||||
{
|
|
||||||
case ShaderIrAsg Asg:
|
|
||||||
{
|
|
||||||
Traverse(Asg, Asg.Dst);
|
|
||||||
Traverse(Asg, Asg.Src);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ShaderIrCond Cond:
|
|
||||||
{
|
|
||||||
Traverse(Cond, Cond.Pred);
|
|
||||||
Traverse(Cond, Cond.Child);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ShaderIrOp Op:
|
|
||||||
{
|
|
||||||
Traverse(Op, Op.OperandA);
|
|
||||||
Traverse(Op, Op.OperandB);
|
|
||||||
Traverse(Op, Op.OperandC);
|
|
||||||
|
|
||||||
if (Op.Inst == ShaderIrInst.Texr ||
|
|
||||||
Op.Inst == ShaderIrInst.Texg ||
|
|
||||||
Op.Inst == ShaderIrInst.Texb ||
|
|
||||||
Op.Inst == ShaderIrInst.Texa)
|
|
||||||
{
|
|
||||||
int Handle = ((ShaderIrOperImm)Op.OperandC).Imm;
|
|
||||||
|
|
||||||
int Index = Handle - TexStartIndex;
|
|
||||||
|
|
||||||
string Name = $"{TextureName}{Index}";
|
|
||||||
|
|
||||||
Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Index));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ShaderIrOperCbuf Cbuf:
|
|
||||||
{
|
|
||||||
string Name = $"{UniformName}{Cbuf.Index}_{Cbuf.Offs}";
|
|
||||||
|
|
||||||
ShaderDeclInfo DeclInfo = new ShaderDeclInfo(Name, Cbuf.Offs, Cbuf.Index);
|
|
||||||
|
|
||||||
Uniforms.TryAdd((Cbuf.Index, Cbuf.Offs), DeclInfo);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ShaderIrOperAbuf Abuf:
|
|
||||||
{
|
|
||||||
int Index = Abuf.Offs >> 4;
|
|
||||||
int Elem = (Abuf.Offs >> 2) & 3;
|
|
||||||
|
|
||||||
int GlslIndex = Index - AttrStartIndex;
|
|
||||||
|
|
||||||
ShaderDeclInfo DeclInfo;
|
|
||||||
|
|
||||||
if (Parent is ShaderIrAsg Asg && Asg.Dst == Node)
|
|
||||||
{
|
|
||||||
if (!OutAttributes.TryGetValue(Index, out DeclInfo))
|
|
||||||
{
|
|
||||||
DeclInfo = new ShaderDeclInfo(OutputName + GlslIndex, GlslIndex);
|
|
||||||
|
|
||||||
OutAttributes.Add(Index, DeclInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!InAttributes.TryGetValue(Index, out DeclInfo))
|
|
||||||
{
|
|
||||||
DeclInfo = new ShaderDeclInfo(InputAttrName + GlslIndex, GlslIndex);
|
|
||||||
|
|
||||||
InAttributes.Add(Index, DeclInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DeclInfo.Enlarge(Elem + 1);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ShaderIrOperGpr Gpr:
|
|
||||||
{
|
|
||||||
if (!Gpr.IsConst && GetNameWithSwizzle(Gprs, Gpr.Index) == null)
|
|
||||||
{
|
|
||||||
string Name = $"{GprName}{Gpr.Index}";
|
|
||||||
|
|
||||||
Gprs.TryAdd(Gpr.Index, new ShaderDeclInfo(Name, Gpr.Index));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ShaderIrOperPred Pred:
|
|
||||||
{
|
|
||||||
if (!Pred.IsConst && GetNameWithSwizzle(Preds, Pred.Index) == null)
|
|
||||||
{
|
|
||||||
string Name = $"{PredName}{Pred.Index}";
|
|
||||||
|
|
||||||
Preds.TryAdd(Pred.Index, new ShaderDeclInfo(Name, Pred.Index));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDeclTextures()
|
private void PrintDeclTextures()
|
||||||
{
|
{
|
||||||
PrintDecls(Textures.Values, "uniform sampler2D");
|
PrintDecls(Decl.Textures, "uniform sampler2D");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDeclUniforms()
|
private void PrintDeclUniforms()
|
||||||
{
|
{
|
||||||
foreach (ShaderDeclInfo DeclInfo in Uniforms.Values.OrderBy(DeclKeySelector))
|
foreach (ShaderDeclInfo DeclInfo in Decl.Uniforms.Values.OrderBy(DeclKeySelector))
|
||||||
{
|
{
|
||||||
SB.AppendLine($"uniform {GetDecl(DeclInfo)};");
|
SB.AppendLine($"uniform {GetDecl(DeclInfo)};");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Uniforms.Values.Count > 0)
|
if (Decl.Uniforms.Count > 0)
|
||||||
{
|
{
|
||||||
SB.AppendLine();
|
SB.AppendLine();
|
||||||
}
|
}
|
||||||
|
@ -254,17 +102,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private void PrintDeclInAttributes()
|
private void PrintDeclInAttributes()
|
||||||
{
|
{
|
||||||
PrintDeclAttributes(InAttributes.Values, "in");
|
PrintDeclAttributes(Decl.InAttributes.Values, "in");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDeclOutAttributes()
|
private void PrintDeclOutAttributes()
|
||||||
{
|
{
|
||||||
PrintDeclAttributes(OutAttributes.Values, "out");
|
PrintDeclAttributes(Decl.OutAttributes.Values, "out");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDeclAttributes(ICollection<ShaderDeclInfo> Decls, string InOut)
|
private void PrintDeclAttributes(IEnumerable<ShaderDeclInfo> Decls, string InOut)
|
||||||
{
|
{
|
||||||
bool PrintNl = false;
|
int Count = 0;
|
||||||
|
|
||||||
foreach (ShaderDeclInfo DeclInfo in Decls.OrderBy(DeclKeySelector))
|
foreach (ShaderDeclInfo DeclInfo in Decls.OrderBy(DeclKeySelector))
|
||||||
{
|
{
|
||||||
|
@ -272,11 +120,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
SB.AppendLine($"layout (location = {DeclInfo.Index}) {InOut} {GetDecl(DeclInfo)};");
|
SB.AppendLine($"layout (location = {DeclInfo.Index}) {InOut} {GetDecl(DeclInfo)};");
|
||||||
|
|
||||||
PrintNl = true;
|
Count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PrintNl)
|
if (Count > 0)
|
||||||
{
|
{
|
||||||
SB.AppendLine();
|
SB.AppendLine();
|
||||||
}
|
}
|
||||||
|
@ -284,33 +132,37 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private void PrintDeclGprs()
|
private void PrintDeclGprs()
|
||||||
{
|
{
|
||||||
PrintDecls(Gprs.Values);
|
PrintDecls(Decl.Gprs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDeclPreds()
|
private void PrintDeclPreds()
|
||||||
{
|
{
|
||||||
PrintDecls(Preds.Values, "bool");
|
PrintDecls(Decl.Preds, "bool");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintDecls(ICollection<ShaderDeclInfo> Decls, string CustomType = null)
|
private void PrintDecls(IReadOnlyDictionary<int, ShaderDeclInfo> Dict, string CustomType = null)
|
||||||
{
|
{
|
||||||
foreach (ShaderDeclInfo DeclInfo in Decls.OrderBy(DeclKeySelector))
|
foreach (ShaderDeclInfo DeclInfo in Dict.Values.OrderBy(DeclKeySelector))
|
||||||
{
|
{
|
||||||
string Name;
|
string Name;
|
||||||
|
|
||||||
if (CustomType != null)
|
if (CustomType != null)
|
||||||
{
|
{
|
||||||
Name = $"{CustomType} {DeclInfo.Name};";
|
Name = CustomType + " " + DeclInfo.Name + ";";
|
||||||
|
}
|
||||||
|
else if (DeclInfo.Name == GlslDecl.FragmentOutputName)
|
||||||
|
{
|
||||||
|
Name = "out " + GetDecl(DeclInfo) + ";";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Name = $"{GetDecl(DeclInfo)};";
|
Name = GetDecl(DeclInfo) + ";";
|
||||||
}
|
}
|
||||||
|
|
||||||
SB.AppendLine(Name);
|
SB.AppendLine(Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Decls.Count > 0)
|
if (Dict.Count > 0)
|
||||||
{
|
{
|
||||||
SB.AppendLine();
|
SB.AppendLine();
|
||||||
}
|
}
|
||||||
|
@ -323,7 +175,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private string GetDecl(ShaderDeclInfo DeclInfo)
|
private string GetDecl(ShaderDeclInfo DeclInfo)
|
||||||
{
|
{
|
||||||
return $"{ElemTypes[DeclInfo.Size - 1]} {DeclInfo.Name}";
|
return ElemTypes[DeclInfo.Size - 1] + " " + DeclInfo.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrintBlockScope(string ScopeName, int IdentationLevel, params ShaderIrNode[] Nodes)
|
private void PrintBlockScope(string ScopeName, int IdentationLevel, params ShaderIrNode[] Nodes)
|
||||||
|
@ -355,17 +207,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
if (Node is ShaderIrCond Cond)
|
if (Node is ShaderIrCond Cond)
|
||||||
{
|
{
|
||||||
string SubScopeName = $"if ({GetInOperName(Cond.Pred, true)})";
|
string SubScopeName = "if (" + GetInOperName(Cond.Pred, true) + ")";
|
||||||
|
|
||||||
PrintBlockScope(SubScopeName, IdentationLevel + 1, Cond.Child);
|
PrintBlockScope(SubScopeName, IdentationLevel + 1, Cond.Child);
|
||||||
}
|
}
|
||||||
else if (Node is ShaderIrAsg Asg && IsValidOutOper(Asg.Dst))
|
else if (Node is ShaderIrAsg Asg && IsValidOutOper(Asg.Dst))
|
||||||
{
|
{
|
||||||
SB.AppendLine($"{Identation}{GetOutOperName(Asg.Dst)} = {GetInOperName(Asg.Src, true)};");
|
SB.AppendLine(Identation + GetOutOperName(Asg.Dst) + " = " + GetInOperName(Asg.Src, true) + ";");
|
||||||
}
|
}
|
||||||
else if (Node is ShaderIrOp Op)
|
else if (Node is ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
SB.AppendLine($"{Identation}{GetInOperName(Op, true)};");
|
SB.AppendLine(Identation + GetInOperName(Op, true) + ";");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -432,7 +284,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
if (!(Entry || IsUnary(Op.Inst)))
|
if (!(Entry || IsUnary(Op.Inst)))
|
||||||
{
|
{
|
||||||
Expr = $"({Expr})";
|
Expr = "(" + Expr + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
return Expr;
|
return Expr;
|
||||||
|
@ -461,7 +313,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private string GetName(ShaderIrOperCbuf Cbuf)
|
private string GetName(ShaderIrOperCbuf Cbuf)
|
||||||
{
|
{
|
||||||
if (!Uniforms.TryGetValue((Cbuf.Index, Cbuf.Offs), out ShaderDeclInfo DeclInfo))
|
if (!Decl.Uniforms.TryGetValue((Cbuf.Index, Cbuf.Offs), out ShaderDeclInfo DeclInfo))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
@ -471,15 +323,15 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private string GetOutAbufName(ShaderIrOperAbuf Abuf)
|
private string GetOutAbufName(ShaderIrOperAbuf Abuf)
|
||||||
{
|
{
|
||||||
return GetName(OutAttributes, Abuf, Swizzle: true);
|
return GetName(Decl.OutAttributes, Abuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetName(ShaderIrOperAbuf Abuf, bool Swizzle = true)
|
private string GetName(ShaderIrOperAbuf Abuf)
|
||||||
{
|
{
|
||||||
return GetName(InAttributes, Abuf, Swizzle);
|
return GetName(Decl.InAttributes, Abuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetName(Dictionary<int, ShaderDeclInfo> Decls, ShaderIrOperAbuf Abuf, bool Swizzle)
|
private string GetName(IReadOnlyDictionary<int, ShaderDeclInfo> Decls, ShaderIrOperAbuf Abuf)
|
||||||
{
|
{
|
||||||
int Index = Abuf.Offs >> 4;
|
int Index = Abuf.Offs >> 4;
|
||||||
int Elem = (Abuf.Offs >> 2) & 3;
|
int Elem = (Abuf.Offs >> 2) & 3;
|
||||||
|
@ -489,14 +341,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
Swizzle &= DeclInfo.Size > 1;
|
return DeclInfo.Size > 1 ? DeclInfo.Name + "." + GetAttrSwizzle(Elem) : DeclInfo.Name;
|
||||||
|
|
||||||
return Swizzle ? $"{DeclInfo.Name}.{GetAttrSwizzle(Elem)}" : DeclInfo.Name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetName(ShaderIrOperGpr Gpr)
|
private string GetName(ShaderIrOperGpr Gpr)
|
||||||
{
|
{
|
||||||
return Gpr.IsConst ? "0" : GetNameWithSwizzle(Gprs, Gpr.Index);
|
return Gpr.IsConst ? "0" : GetNameWithSwizzle(Decl.Gprs, Gpr.Index);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetName(ShaderIrOperImm Imm)
|
private string GetName(ShaderIrOperImm Imm)
|
||||||
|
@ -506,10 +356,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private string GetName(ShaderIrOperPred Pred)
|
private string GetName(ShaderIrOperPred Pred)
|
||||||
{
|
{
|
||||||
return Pred.IsConst ? "true" : GetNameWithSwizzle(Preds, Pred.Index);
|
return Pred.IsConst ? "true" : GetNameWithSwizzle(Decl.Preds, Pred.Index);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetNameWithSwizzle(Dictionary<int, ShaderDeclInfo> Decls, int Index)
|
private string GetNameWithSwizzle(IReadOnlyDictionary<int, ShaderDeclInfo> Decls, int Index)
|
||||||
{
|
{
|
||||||
int VecIndex = Index >> 2;
|
int VecIndex = Index >> 2;
|
||||||
|
|
||||||
|
@ -517,137 +367,82 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
if (DeclInfo.Size > 1 && Index < VecIndex + DeclInfo.Size)
|
if (DeclInfo.Size > 1 && Index < VecIndex + DeclInfo.Size)
|
||||||
{
|
{
|
||||||
return $"{DeclInfo.Name}.{GetAttrSwizzle(Index & 3)}";
|
return DeclInfo.Name + "." + GetAttrSwizzle(Index & 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Decls.TryGetValue(Index, out DeclInfo))
|
if (!Decls.TryGetValue(Index, out DeclInfo))
|
||||||
{
|
{
|
||||||
return null;
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeclInfo.Name;
|
return DeclInfo.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetBandExpr(ShaderIrOp Op)
|
private string GetAttrSwizzle(int Elem)
|
||||||
{
|
{
|
||||||
return $"{GetInOperName(Op.OperandA)} && " +
|
return "xyzw".Substring(Elem, 1);
|
||||||
$"{GetInOperName(Op.OperandB)}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetBnotExpr(ShaderIrOp Op)
|
private string GetBandExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "&&");
|
||||||
|
private string GetBnotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "!");
|
||||||
|
|
||||||
|
private string GetCltExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<");
|
||||||
|
private string GetCeqExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "==");
|
||||||
|
private string GetCleExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<=");
|
||||||
|
private string GetCgtExpr(ShaderIrOp Op) => GetBinaryExpr(Op, ">");
|
||||||
|
private string GetCneExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "!=");
|
||||||
|
private string GetCgeExpr(ShaderIrOp Op) => GetBinaryExpr(Op, ">=");
|
||||||
|
|
||||||
|
private string GetExitExpr(ShaderIrOp Op) => "return";
|
||||||
|
|
||||||
|
private string GetFabsExpr(ShaderIrOp Op) => GetUnaryCall(Op, "abs");
|
||||||
|
|
||||||
|
private string GetFaddExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "+");
|
||||||
|
|
||||||
|
private string GetFcosExpr(ShaderIrOp Op) => GetUnaryCall(Op, "cos");
|
||||||
|
|
||||||
|
private string GetFex2Expr(ShaderIrOp Op) => GetUnaryCall(Op, "exp2");
|
||||||
|
|
||||||
|
private string GetFfmaExpr(ShaderIrOp Op) => GetTernaryExpr(Op, "*", "+");
|
||||||
|
|
||||||
|
private string GetFlg2Expr(ShaderIrOp Op) => GetUnaryCall(Op, "log2");
|
||||||
|
|
||||||
|
private string GetFmulExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "*");
|
||||||
|
|
||||||
|
private string GetFnegExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "-");
|
||||||
|
|
||||||
|
private string GetFrcpExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "1 / ");
|
||||||
|
|
||||||
|
private string GetFrsqExpr(ShaderIrOp Op) => GetUnaryCall(Op, "inversesqrt");
|
||||||
|
|
||||||
|
private string GetFsinExpr(ShaderIrOp Op) => GetUnaryCall(Op, "sin");
|
||||||
|
|
||||||
|
private string GetIpaExpr(ShaderIrOp Op) => GetInOperName(Op.OperandA);
|
||||||
|
|
||||||
|
private string GetKilExpr(ShaderIrOp Op) => "discard";
|
||||||
|
|
||||||
|
private string GetUnaryCall(ShaderIrOp Op, string FuncName)
|
||||||
{
|
{
|
||||||
return $"!{GetInOperName(Op.OperandA)}";
|
return FuncName + "(" + GetInOperName(Op.OperandA) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetCltExpr(ShaderIrOp Op)
|
private string GetUnaryExpr(ShaderIrOp Op, string Opr)
|
||||||
{
|
{
|
||||||
return $"{GetInOperName(Op.OperandA)} < " +
|
return Opr + GetInOperName(Op.OperandA);
|
||||||
$"{GetInOperName(Op.OperandB)}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetCeqExpr(ShaderIrOp Op)
|
private string GetBinaryExpr(ShaderIrOp Op, string Opr)
|
||||||
{
|
{
|
||||||
return $"{GetInOperName(Op.OperandA)} == " +
|
return GetInOperName(Op.OperandA) + " " + Opr + " " +
|
||||||
$"{GetInOperName(Op.OperandB)}";
|
GetInOperName(Op.OperandB);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetCleExpr(ShaderIrOp Op)
|
private string GetTernaryExpr(ShaderIrOp Op, string Opr1, string Opr2)
|
||||||
{
|
{
|
||||||
return $"{GetInOperName(Op.OperandA)} <= " +
|
return GetInOperName(Op.OperandA) + " " + Opr1 + " " +
|
||||||
$"{GetInOperName(Op.OperandB)}";
|
GetInOperName(Op.OperandB) + " " + Opr2 + " " +
|
||||||
}
|
GetInOperName(Op.OperandC);
|
||||||
|
|
||||||
private string GetCgtExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"{GetInOperName(Op.OperandA)} > " +
|
|
||||||
$"{GetInOperName(Op.OperandB)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetCneExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"{GetInOperName(Op.OperandA)} != " +
|
|
||||||
$"{GetInOperName(Op.OperandB)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetCgeExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"{GetInOperName(Op.OperandA)} >= " +
|
|
||||||
$"{GetInOperName(Op.OperandB)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetExitExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return "return";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetFabsExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"abs({GetInOperName(Op.OperandA)})";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetFaddExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"{GetInOperName(Op.OperandA)} + " +
|
|
||||||
$"{GetInOperName(Op.OperandB)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetFcosExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"cos({GetInOperName(Op.OperandA)})";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetFex2Expr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"exp2({GetInOperName(Op.OperandA)})";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetFfmaExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"{GetInOperName(Op.OperandA)} * " +
|
|
||||||
$"{GetInOperName(Op.OperandB)} + " +
|
|
||||||
$"{GetInOperName(Op.OperandC)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetFlg2Expr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"log2({GetInOperName(Op.OperandA)})";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetFmulExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"{GetInOperName(Op.OperandA)} * " +
|
|
||||||
$"{GetInOperName(Op.OperandB)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetFnegExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"-{GetInOperName(Op.OperandA)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetFrcpExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"1 / {GetInOperName(Op.OperandA)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetFrsqExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"inversesqrt({GetInOperName(Op.OperandA)})";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetFsinExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return $"sin({GetInOperName(Op.OperandA)})";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetIpaExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return GetInOperName(Op.OperandA);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetKilExpr(ShaderIrOp Op)
|
|
||||||
{
|
|
||||||
return "discard";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetTexrExpr(ShaderIrOp Op) => GetTexExpr(Op, 'r');
|
private string GetTexrExpr(ShaderIrOp Op) => GetTexExpr(Op, 'r');
|
||||||
|
@ -666,7 +461,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
int Handle = ((ShaderIrOperImm)Op.OperandC).Imm;
|
int Handle = ((ShaderIrOperImm)Op.OperandC).Imm;
|
||||||
|
|
||||||
if (!Textures.TryGetValue(Handle, out ShaderDeclInfo DeclInfo))
|
if (!Decl.Textures.TryGetValue(Handle, out ShaderDeclInfo DeclInfo))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
@ -676,40 +471,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
private string GetTexSamplerCoords(ShaderIrOp Op)
|
private string GetTexSamplerCoords(ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
if (GetInnerNode(Op.OperandA) is ShaderIrOperAbuf AAbuf &&
|
|
||||||
GetInnerNode(Op.OperandB) is ShaderIrOperAbuf BAbuf)
|
|
||||||
{
|
|
||||||
if (AAbuf.GprIndex == ShaderIrOperGpr.ZRIndex &&
|
|
||||||
BAbuf.GprIndex == ShaderIrOperGpr.ZRIndex &&
|
|
||||||
(AAbuf.Offs >> 4) == (BAbuf.Offs >> 4))
|
|
||||||
{
|
|
||||||
//Needs to call this to ensure it registers all elements used.
|
|
||||||
GetName(BAbuf);
|
|
||||||
|
|
||||||
return $"{GetName(AAbuf, Swizzle: false)}." +
|
|
||||||
$"{GetAttrSwizzle((AAbuf.Offs >> 2) & 3)}" +
|
|
||||||
$"{GetAttrSwizzle((BAbuf.Offs >> 2) & 3)}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "vec2(" +
|
return "vec2(" +
|
||||||
$"{GetInOperName(Op.OperandA)}, " +
|
GetInOperName(Op.OperandA) + ", " +
|
||||||
$"{GetInOperName(Op.OperandB)})";
|
GetInOperName(Op.OperandB) + ")";
|
||||||
}
|
|
||||||
|
|
||||||
private ShaderIrNode GetInnerNode(ShaderIrNode Node)
|
|
||||||
{
|
|
||||||
if (Node is ShaderIrOp Op && Op.Inst == ShaderIrInst.Ipa)
|
|
||||||
{
|
|
||||||
return Op.OperandA;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Node;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetAttrSwizzle(int Elem)
|
|
||||||
{
|
|
||||||
return "xyzw".Substring(Elem, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,13 +6,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
public string Code { get; private set; }
|
public string Code { get; private set; }
|
||||||
|
|
||||||
public ICollection<ShaderDeclInfo> Textures { get; private set; }
|
public IEnumerable<ShaderDeclInfo> Textures { get; private set; }
|
||||||
public ICollection<ShaderDeclInfo> Uniforms { get; private set; }
|
public IEnumerable<ShaderDeclInfo> Uniforms { get; private set; }
|
||||||
|
|
||||||
public GlslProgram(
|
public GlslProgram(
|
||||||
string Code,
|
string Code,
|
||||||
ICollection<ShaderDeclInfo> Textures,
|
IEnumerable<ShaderDeclInfo> Textures,
|
||||||
ICollection<ShaderDeclInfo> Uniforms)
|
IEnumerable<ShaderDeclInfo> Uniforms)
|
||||||
{
|
{
|
||||||
this.Code = Code;
|
this.Code = Code;
|
||||||
this.Textures = Textures;
|
this.Textures = Textures;
|
||||||
|
|
|
@ -41,6 +41,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
}
|
}
|
||||||
|
|
||||||
AddMethod(0x585, 1, 1, VertexEndGl);
|
AddMethod(0x585, 1, 1, VertexEndGl);
|
||||||
|
AddMethod(0x674, 1, 1, ClearBuffers);
|
||||||
AddMethod(0x6c3, 1, 1, QueryControl);
|
AddMethod(0x6c3, 1, 1, QueryControl);
|
||||||
AddMethod(0x8e4, 16, 1, CbData);
|
AddMethod(0x8e4, 16, 1, CbData);
|
||||||
AddMethod(0x904, 1, 1, CbBind);
|
AddMethod(0x904, 1, 1, CbBind);
|
||||||
|
@ -66,18 +67,42 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
int TexHandle = ReadCb(Memory, TexCbuf, 0x20);
|
int TexHandle = ReadCb(Memory, TexCbuf, 0x20);
|
||||||
|
|
||||||
|
UploadShaders(Memory);
|
||||||
|
|
||||||
|
Gpu.Renderer.BindProgram();
|
||||||
|
|
||||||
|
UploadUniforms(Memory);
|
||||||
|
UploadVertexArrays(Memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearBuffers(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||||
|
{
|
||||||
|
int Arg0 = PBEntry.Arguments[0];
|
||||||
|
|
||||||
|
int Rt = (Arg0 >> 6) & 0xf;
|
||||||
|
|
||||||
|
GalClearBufferFlags Flags = (GalClearBufferFlags)(Arg0 & 0x3f);
|
||||||
|
|
||||||
|
Gpu.Renderer.ClearBuffers(Rt, Flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UploadShaders(AMemory Memory)
|
||||||
|
{
|
||||||
long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
||||||
|
|
||||||
for (int Index = 0; Index < 6; Index++)
|
for (int Index = 0; Index < 6; Index++)
|
||||||
{
|
{
|
||||||
int Offset = ReadRegister(NvGpuEngine3dReg.ShaderOffset + Index * 0x10);
|
int Control = ReadRegister(NvGpuEngine3dReg.ShaderNControl + Index * 0x10);
|
||||||
|
int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + Index * 0x10);
|
||||||
|
|
||||||
if (Offset == 0)
|
if (Offset == 0 || (Index != 1 && Index != 5))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
long Position = Gpu.GetCpuAddr(BasePosition + (uint)Offset);
|
long Tag = BasePosition + (uint)Offset;
|
||||||
|
|
||||||
|
long Position = Gpu.GetCpuAddr(Tag);
|
||||||
|
|
||||||
if (Position == -1)
|
if (Position == -1)
|
||||||
{
|
{
|
||||||
|
@ -91,7 +116,25 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
GalShaderType ShaderType = GetTypeFromProgram(Index);
|
GalShaderType ShaderType = GetTypeFromProgram(Index);
|
||||||
|
|
||||||
Gpu.Renderer.CreateShader(Position, Code, ShaderType);
|
Gpu.Renderer.CreateShader(Tag, ShaderType, Code);
|
||||||
|
Gpu.Renderer.BindShader(Tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UploadUniforms(AMemory Memory)
|
||||||
|
{
|
||||||
|
long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
||||||
|
|
||||||
|
for (int Index = 0; Index < 5; Index++)
|
||||||
|
{
|
||||||
|
int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + (Index + 1) * 0x10);
|
||||||
|
|
||||||
|
long Tag = BasePosition + (uint)Offset;
|
||||||
|
|
||||||
|
if (Offset == 0 || (Index != 0 && Index != 4))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (int Cbuf = 0; Cbuf < Cbs.Length; Cbuf++)
|
for (int Cbuf = 0; Cbuf < Cbs.Length; Cbuf++)
|
||||||
{
|
{
|
||||||
|
@ -99,16 +142,68 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
if (Cb.Enabled)
|
if (Cb.Enabled)
|
||||||
{
|
{
|
||||||
long CbPosition = Cb.Position + (int)ShaderType * Cb.Size;
|
long CbPosition = Cb.Position + Index * Cb.Size;
|
||||||
|
|
||||||
byte[] Data = AMemoryHelper.ReadBytes(Memory, CbPosition, (uint)Cb.Size);
|
byte[] Data = AMemoryHelper.ReadBytes(Memory, CbPosition, (uint)Cb.Size);
|
||||||
|
|
||||||
Gpu.Renderer.SetShaderCb(Position, Cbuf, Data);
|
Gpu.Renderer.SetShaderCb(Tag, Cbuf, Data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UploadVertexArrays(AMemory Memory)
|
||||||
|
{
|
||||||
|
List<GalVertexAttrib>[] Attribs = new List<GalVertexAttrib>[32];
|
||||||
|
|
||||||
|
for (int Attr = 0; Attr < 16; Attr++)
|
||||||
|
{
|
||||||
|
int Packed = ReadRegister(NvGpuEngine3dReg.VertexAttribNFormat + Attr);
|
||||||
|
|
||||||
|
int ArrayIndex = Packed & 0x1f;
|
||||||
|
|
||||||
|
if (Attribs[ArrayIndex] == null)
|
||||||
|
{
|
||||||
|
Attribs[ArrayIndex] = new List<GalVertexAttrib>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Attribs[ArrayIndex].Add(new GalVertexAttrib(
|
||||||
|
((Packed >> 6) & 0x1) != 0,
|
||||||
|
(Packed >> 7) & 0x3fff,
|
||||||
|
(GalVertexAttribSize)((Packed >> 21) & 0x3f),
|
||||||
|
(GalVertexAttribType)((Packed >> 27) & 0x7),
|
||||||
|
((Packed >> 31) & 0x1) != 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int Index = 0; Index < 32; Index++)
|
||||||
|
{
|
||||||
|
int Control = ReadRegister(NvGpuEngine3dReg.VertexArrayNControl + Index * 4);
|
||||||
|
|
||||||
|
bool Enable = (Control & 0x1000) != 0;
|
||||||
|
|
||||||
|
if (!Enable)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4);
|
||||||
|
long EndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + Index * 4);
|
||||||
|
|
||||||
|
long Size = (EndPos - Position) + 1;
|
||||||
|
|
||||||
|
int Stride = Control & 0xfff;
|
||||||
|
|
||||||
|
Position = Gpu.GetCpuAddr(Position);
|
||||||
|
|
||||||
|
byte[] Data = AMemoryHelper.ReadBytes(Memory, Position, Size);
|
||||||
|
|
||||||
|
GalVertexAttrib[] AttribArray = Attribs[Index]?.ToArray() ?? new GalVertexAttrib[0];
|
||||||
|
|
||||||
|
Gpu.Renderer.SetVertexArray(Index, Stride, Data, AttribArray);
|
||||||
|
Gpu.Renderer.RenderVertexArray(Index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static GalShaderType GetTypeFromProgram(int Program)
|
private static GalShaderType GetTypeFromProgram(int Program)
|
||||||
{
|
{
|
||||||
switch (Program)
|
switch (Program)
|
||||||
|
@ -145,9 +240,9 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
private void CbData(AMemory Memory, NsGpuPBEntry PBEntry)
|
private void CbData(AMemory Memory, NsGpuPBEntry PBEntry)
|
||||||
{
|
{
|
||||||
if (TryGetCpuAddr(NvGpuEngine3dReg.CbAddress, out long Position))
|
if (TryGetCpuAddr(NvGpuEngine3dReg.ConstBufferNAddress, out long Position))
|
||||||
{
|
{
|
||||||
int Offset = ReadRegister(NvGpuEngine3dReg.CbOffset);
|
int Offset = ReadRegister(NvGpuEngine3dReg.ConstBufferNOffset);
|
||||||
|
|
||||||
foreach (int Arg in PBEntry.Arguments)
|
foreach (int Arg in PBEntry.Arguments)
|
||||||
{
|
{
|
||||||
|
@ -156,7 +251,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
Offset += 4;
|
Offset += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteRegister(NvGpuEngine3dReg.CbOffset, Offset);
|
WriteRegister(NvGpuEngine3dReg.ConstBufferNOffset, Offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,11 +263,11 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
|
|
||||||
Index = (Index >> 4) & 0x1f;
|
Index = (Index >> 4) & 0x1f;
|
||||||
|
|
||||||
if (TryGetCpuAddr(NvGpuEngine3dReg.CbAddress, out long Position))
|
if (TryGetCpuAddr(NvGpuEngine3dReg.ConstBufferNAddress, out long Position))
|
||||||
{
|
{
|
||||||
Cbs[Index].Position = Position;
|
Cbs[Index].Position = Position;
|
||||||
Cbs[Index].Enabled = Enabled;
|
Cbs[Index].Enabled = Enabled;
|
||||||
Cbs[Index].Size = ReadRegister(NvGpuEngine3dReg.CbSize);
|
Cbs[Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferNSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,22 @@ namespace Ryujinx.Graphics.Gpu
|
||||||
{
|
{
|
||||||
enum NvGpuEngine3dReg
|
enum NvGpuEngine3dReg
|
||||||
{
|
{
|
||||||
ShaderAddress = 0x582,
|
VertexAttribNFormat = 0x458,
|
||||||
QueryAddress = 0x6c0,
|
ShaderAddress = 0x582,
|
||||||
QuerySequence = 0x6c2,
|
QueryAddress = 0x6c0,
|
||||||
QueryControl = 0x6c3,
|
QuerySequence = 0x6c2,
|
||||||
ShaderControl = 0x800,
|
QueryControl = 0x6c3,
|
||||||
ShaderOffset = 0x801,
|
VertexArrayNControl = 0x700,
|
||||||
ShaderMaxGprs = 0x803,
|
VertexArrayNAddress = 0x701,
|
||||||
ShaderType = 0x804,
|
VertexArrayNDivisor = 0x703,
|
||||||
CbSize = 0x8e0,
|
VertexArrayNEndAddr = 0x7c0,
|
||||||
CbAddress = 0x8e1,
|
ShaderNControl = 0x800,
|
||||||
CbOffset = 0x8e3,
|
ShaderNOffset = 0x801,
|
||||||
TextureCbIndex = 0x982
|
ShaderNMaxGprs = 0x803,
|
||||||
|
ShaderNType = 0x804,
|
||||||
|
ConstBufferNSize = 0x8e0,
|
||||||
|
ConstBufferNAddress = 0x8e1,
|
||||||
|
ConstBufferNOffset = 0x8e3,
|
||||||
|
TextureCbIndex = 0x982
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -173,8 +173,6 @@ namespace Ryujinx
|
||||||
Title = $"Ryujinx Screen - (Vsync: {VSync} - FPS: {Ns.Statistics.SystemFrameRate:0} - Guest FPS: " +
|
Title = $"Ryujinx Screen - (Vsync: {VSync} - FPS: {Ns.Statistics.SystemFrameRate:0} - Guest FPS: " +
|
||||||
$"{Ns.Statistics.GameFrameRate:0})";
|
$"{Ns.Statistics.GameFrameRate:0})";
|
||||||
|
|
||||||
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
|
|
||||||
|
|
||||||
Renderer.RunActions();
|
Renderer.RunActions();
|
||||||
Renderer.Render();
|
Renderer.Render();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue