Refactoring OGLRenderer rasterizer, some cleanup on the glsl decompiler
This commit is contained in:
parent
bac72e1613
commit
1132b6edae
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 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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -219,7 +219,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
PixelFormat.Rgba,
|
||||
PixelType.UnsignedByte,
|
||||
Pixels);
|
||||
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
|
||||
GL.BindVertexArray(VaoHandle);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
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 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) + ")";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue