Refactoring OGLRenderer rasterizer, some cleanup on the glsl decompiler

This commit is contained in:
gdkchan 2018-03-31 23:58:26 -03:00
parent bac72e1613
commit 1132b6edae
13 changed files with 666 additions and 581 deletions

View 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
}
}

View file

@ -2,8 +2,6 @@ namespace Ryujinx.Graphics.Gal
{
public struct GalVertexAttrib
{
public int Index { get; private set; }
public int Buffer { get; private set; }
public bool IsConst { get; private set; }
public int Offset { get; private set; }
@ -13,16 +11,12 @@ namespace Ryujinx.Graphics.Gal
public bool IsBgra { get; private set; }
public GalVertexAttrib(
int Index,
int Buffer,
bool IsConst,
int Offset,
GalVertexAttribSize Size,
GalVertexAttribType Type,
bool IsBgra)
{
this.Index = Index;
this.Buffer = Buffer;
this.IsConst = IsConst;
this.Offset = Offset;
this.Size = Size;

View file

@ -21,12 +21,17 @@ namespace Ryujinx.Graphics.Gal
float OffsY,
float Rotate);
//Rasterizer
void ClearBuffers(int RtIndex, GalClearBufferFlags Flags);
void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs);
void RenderVertexArray(int VbIndex);
//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 BindShader(long Tag);
void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs);
void BindProgram();
void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height);

View file

@ -219,7 +219,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
PixelFormat.Rgba,
PixelType.UnsignedByte,
Pixels);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindVertexArray(VaoHandle);

View file

@ -1,7 +1,178 @@
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Gal.OpenGL
{
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;
}
}
}

View file

@ -15,13 +15,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public GalShaderType Type { get; private set; }
public ICollection<ShaderDeclInfo> TextureUsage { get; private set; }
public ICollection<ShaderDeclInfo> UniformUsage { get; private set; }
public IEnumerable<ShaderDeclInfo> TextureUsage { get; private set; }
public IEnumerable<ShaderDeclInfo> UniformUsage { get; private set; }
public ShaderStage(
GalShaderType Type,
ICollection<ShaderDeclInfo> TextureUsage,
ICollection<ShaderDeclInfo> UniformUsage)
IEnumerable<ShaderDeclInfo> TextureUsage,
IEnumerable<ShaderDeclInfo> UniformUsage)
{
Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
@ -61,6 +61,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
private Dictionary<ShaderProgram, int> Programs;
public int CurrentProgramHandle { get; private set; }
public OGLShader()
{
Stages = new Dictionary<long, ShaderStage>();
@ -68,14 +70,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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))
{
GlslProgram Program = GetGlslProgram(Data, Type);
System.Console.WriteLine(Program.Code);
ShaderStage Stage = new ShaderStage(
Type,
Program.Textures,
@ -94,6 +94,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage.Where(x => x.Cbuf == Cbuf))
{
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 ||
Current.Fragment == null)
{
return false;
return;
}
GL.UseProgram(GetCurrentProgramHandle());
return true;
}
private int GetCurrentProgramHandle()
{
if (!Programs.TryGetValue(Current, out int Handle))
{
Handle = GL.CreateProgram();
@ -145,7 +142,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Programs.Add(Current, Handle);
}
return Handle;
GL.UseProgram(Handle);
CurrentProgramHandle = Handle;
}
private void AttachIfNotNull(int ProgramHandle, ShaderStage Stage)

View file

@ -2,29 +2,20 @@ using OpenTK;
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Gal.OpenGL
{
public class OpenGLRenderer : IGalRenderer
{
private struct VertexBuffer
{
public int VaoHandle;
public int VboHandle;
public int PrimCount;
}
private struct Texture
{
public int Handle;
}
private List<VertexBuffer> VertexBuffers;
private Texture[] Textures;
private OGLRasterizer Rasterizer;
private OGLShader Shader;
private ConcurrentQueue<Action> ActionsQueue;
@ -33,10 +24,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public OpenGLRenderer()
{
VertexBuffers = new List<VertexBuffer>();
Textures = new Texture[8];
Rasterizer = new OGLRasterizer();
Shader = new OGLShader();
ActionsQueue = new ConcurrentQueue<Action>();
@ -70,18 +61,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public void 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)
@ -110,157 +89,31 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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);
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);
ActionsQueue.Enqueue(() => Rasterizer.RenderVertexArray(VbIndex));
}
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);
}
public void CreateShader(long Tag, byte[] Data, GalShaderType Type)
public void CreateShader(long Tag, GalShaderType Type, byte[] Data)
{
if (Data == null)
{
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)
@ -315,26 +168,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
ActionsQueue.Enqueue(() => Shader.Bind(Tag));
}
private void EnsureVbInitialized(int VbIndex)
public void BindProgram()
{
while (VbIndex >= VertexBuffers.Count)
{
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;
ActionsQueue.Enqueue(() => Shader.BindProgram());
}
private void EnsureTexInitialized(int TexIndex)

View 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);
}
}
}

View file

@ -16,26 +16,7 @@ namespace Ryujinx.Graphics.Gal.Shader
private static string[] ElemTypes = new string[] { "float", "vec2", "vec3", "vec4" };
private Dictionary<int, ShaderDeclInfo> Textures;
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 GlslDecl Decl;
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>();
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);
ShaderIrBlock Block = ShaderDecoder.DecodeBasicBlock(Code, 0, ShaderType);
ShaderIrNode[] Nodes = Block.GetNodes();
foreach (ShaderIrNode Node in Nodes)
{
Traverse(null, Node);
}
Decl = new GlslDecl(Nodes, ShaderType);
SB = new StringBuilder();
SB.AppendLine("#version 430");
@ -120,133 +78,23 @@ namespace Ryujinx.Graphics.Gal.Shader
return new GlslProgram(
GlslCode,
Textures.Values,
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;
}
}
Decl.Textures.Values,
Decl.Uniforms.Values);
}
private void PrintDeclTextures()
{
PrintDecls(Textures.Values, "uniform sampler2D");
PrintDecls(Decl.Textures, "uniform sampler2D");
}
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)};");
}
if (Uniforms.Values.Count > 0)
if (Decl.Uniforms.Count > 0)
{
SB.AppendLine();
}
@ -254,17 +102,17 @@ namespace Ryujinx.Graphics.Gal.Shader
private void PrintDeclInAttributes()
{
PrintDeclAttributes(InAttributes.Values, "in");
PrintDeclAttributes(Decl.InAttributes.Values, "in");
}
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))
{
@ -272,11 +120,11 @@ namespace Ryujinx.Graphics.Gal.Shader
{
SB.AppendLine($"layout (location = {DeclInfo.Index}) {InOut} {GetDecl(DeclInfo)};");
PrintNl = true;
Count++;
}
}
if (PrintNl)
if (Count > 0)
{
SB.AppendLine();
}
@ -284,33 +132,37 @@ namespace Ryujinx.Graphics.Gal.Shader
private void PrintDeclGprs()
{
PrintDecls(Gprs.Values);
PrintDecls(Decl.Gprs);
}
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;
if (CustomType != null)
{
Name = $"{CustomType} {DeclInfo.Name};";
Name = CustomType + " " + DeclInfo.Name + ";";
}
else if (DeclInfo.Name == GlslDecl.FragmentOutputName)
{
Name = "out " + GetDecl(DeclInfo) + ";";
}
else
{
Name = $"{GetDecl(DeclInfo)};";
Name = GetDecl(DeclInfo) + ";";
}
SB.AppendLine(Name);
}
if (Decls.Count > 0)
if (Dict.Count > 0)
{
SB.AppendLine();
}
@ -323,7 +175,7 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
@ -355,17 +207,17 @@ namespace Ryujinx.Graphics.Gal.Shader
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);
}
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)
{
SB.AppendLine($"{Identation}{GetInOperName(Op, true)};");
SB.AppendLine(Identation + GetInOperName(Op, true) + ";");
}
else
{
@ -432,7 +284,7 @@ namespace Ryujinx.Graphics.Gal.Shader
if (!(Entry || IsUnary(Op.Inst)))
{
Expr = $"({Expr})";
Expr = "(" + Expr + ")";
}
return Expr;
@ -461,7 +313,7 @@ namespace Ryujinx.Graphics.Gal.Shader
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();
}
@ -471,15 +323,15 @@ namespace Ryujinx.Graphics.Gal.Shader
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 Elem = (Abuf.Offs >> 2) & 3;
@ -489,14 +341,12 @@ namespace Ryujinx.Graphics.Gal.Shader
throw new InvalidOperationException();
}
Swizzle &= DeclInfo.Size > 1;
return Swizzle ? $"{DeclInfo.Name}.{GetAttrSwizzle(Elem)}" : DeclInfo.Name;
return DeclInfo.Size > 1 ? DeclInfo.Name + "." + GetAttrSwizzle(Elem) : DeclInfo.Name;
}
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)
@ -506,10 +356,10 @@ namespace Ryujinx.Graphics.Gal.Shader
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;
@ -517,137 +367,82 @@ namespace Ryujinx.Graphics.Gal.Shader
{
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))
{
return null;
throw new InvalidOperationException();
}
return DeclInfo.Name;
}
private string GetBandExpr(ShaderIrOp Op)
private string GetAttrSwizzle(int Elem)
{
return $"{GetInOperName(Op.OperandA)} && " +
$"{GetInOperName(Op.OperandB)}";
return "xyzw".Substring(Elem, 1);
}
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)} < " +
$"{GetInOperName(Op.OperandB)}";
return Opr + GetInOperName(Op.OperandA);
}
private string GetCeqExpr(ShaderIrOp Op)
private string GetBinaryExpr(ShaderIrOp Op, string Opr)
{
return $"{GetInOperName(Op.OperandA)} == " +
$"{GetInOperName(Op.OperandB)}";
return GetInOperName(Op.OperandA) + " " + Opr + " " +
GetInOperName(Op.OperandB);
}
private string GetCleExpr(ShaderIrOp Op)
private string GetTernaryExpr(ShaderIrOp Op, string Opr1, string Opr2)
{
return $"{GetInOperName(Op.OperandA)} <= " +
$"{GetInOperName(Op.OperandB)}";
}
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";
return GetInOperName(Op.OperandA) + " " + Opr1 + " " +
GetInOperName(Op.OperandB) + " " + Opr2 + " " +
GetInOperName(Op.OperandC);
}
private string GetTexrExpr(ShaderIrOp Op) => GetTexExpr(Op, 'r');
@ -666,7 +461,7 @@ namespace Ryujinx.Graphics.Gal.Shader
int Handle = ((ShaderIrOperImm)Op.OperandC).Imm;
if (!Textures.TryGetValue(Handle, out ShaderDeclInfo DeclInfo))
if (!Decl.Textures.TryGetValue(Handle, out ShaderDeclInfo DeclInfo))
{
throw new InvalidOperationException();
}
@ -676,40 +471,9 @@ namespace Ryujinx.Graphics.Gal.Shader
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(" +
$"{GetInOperName(Op.OperandA)}, " +
$"{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);
GetInOperName(Op.OperandA) + ", " +
GetInOperName(Op.OperandB) + ")";
}
}
}

View file

@ -6,13 +6,13 @@ namespace Ryujinx.Graphics.Gal.Shader
{
public string Code { get; private set; }
public ICollection<ShaderDeclInfo> Textures { get; private set; }
public ICollection<ShaderDeclInfo> Uniforms { get; private set; }
public IEnumerable<ShaderDeclInfo> Textures { get; private set; }
public IEnumerable<ShaderDeclInfo> Uniforms { get; private set; }
public GlslProgram(
string Code,
ICollection<ShaderDeclInfo> Textures,
ICollection<ShaderDeclInfo> Uniforms)
IEnumerable<ShaderDeclInfo> Textures,
IEnumerable<ShaderDeclInfo> Uniforms)
{
this.Code = Code;
this.Textures = Textures;

View file

@ -41,6 +41,7 @@ namespace Ryujinx.Graphics.Gpu
}
AddMethod(0x585, 1, 1, VertexEndGl);
AddMethod(0x674, 1, 1, ClearBuffers);
AddMethod(0x6c3, 1, 1, QueryControl);
AddMethod(0x8e4, 16, 1, CbData);
AddMethod(0x904, 1, 1, CbBind);
@ -66,18 +67,42 @@ namespace Ryujinx.Graphics.Gpu
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);
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;
}
long Position = Gpu.GetCpuAddr(BasePosition + (uint)Offset);
long Tag = BasePosition + (uint)Offset;
long Position = Gpu.GetCpuAddr(Tag);
if (Position == -1)
{
@ -91,7 +116,25 @@ namespace Ryujinx.Graphics.Gpu
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++)
{
@ -99,16 +142,68 @@ namespace Ryujinx.Graphics.Gpu
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);
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)
{
switch (Program)
@ -145,9 +240,9 @@ namespace Ryujinx.Graphics.Gpu
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)
{
@ -156,7 +251,7 @@ namespace Ryujinx.Graphics.Gpu
Offset += 4;
}
WriteRegister(NvGpuEngine3dReg.CbOffset, Offset);
WriteRegister(NvGpuEngine3dReg.ConstBufferNOffset, Offset);
}
}
@ -168,11 +263,11 @@ namespace Ryujinx.Graphics.Gpu
Index = (Index >> 4) & 0x1f;
if (TryGetCpuAddr(NvGpuEngine3dReg.CbAddress, out long Position))
if (TryGetCpuAddr(NvGpuEngine3dReg.ConstBufferNAddress, out long Position))
{
Cbs[Index].Position = Position;
Cbs[Index].Enabled = Enabled;
Cbs[Index].Size = ReadRegister(NvGpuEngine3dReg.CbSize);
Cbs[Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferNSize);
}
}

View file

@ -2,17 +2,22 @@ namespace Ryujinx.Graphics.Gpu
{
enum NvGpuEngine3dReg
{
ShaderAddress = 0x582,
QueryAddress = 0x6c0,
QuerySequence = 0x6c2,
QueryControl = 0x6c3,
ShaderControl = 0x800,
ShaderOffset = 0x801,
ShaderMaxGprs = 0x803,
ShaderType = 0x804,
CbSize = 0x8e0,
CbAddress = 0x8e1,
CbOffset = 0x8e3,
TextureCbIndex = 0x982
VertexAttribNFormat = 0x458,
ShaderAddress = 0x582,
QueryAddress = 0x6c0,
QuerySequence = 0x6c2,
QueryControl = 0x6c3,
VertexArrayNControl = 0x700,
VertexArrayNAddress = 0x701,
VertexArrayNDivisor = 0x703,
VertexArrayNEndAddr = 0x7c0,
ShaderNControl = 0x800,
ShaderNOffset = 0x801,
ShaderNMaxGprs = 0x803,
ShaderNType = 0x804,
ConstBufferNSize = 0x8e0,
ConstBufferNAddress = 0x8e1,
ConstBufferNOffset = 0x8e3,
TextureCbIndex = 0x982
}
}

View file

@ -173,8 +173,6 @@ namespace Ryujinx
Title = $"Ryujinx Screen - (Vsync: {VSync} - FPS: {Ns.Statistics.SystemFrameRate:0} - Guest FPS: " +
$"{Ns.Statistics.GameFrameRate:0})";
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
Renderer.RunActions();
Renderer.Render();