diff --git a/ChocolArm64/Instruction/ASoftFallback.cs b/ChocolArm64/Instruction/ASoftFallback.cs index 6a407baf0..d626622ab 100644 --- a/ChocolArm64/Instruction/ASoftFallback.cs +++ b/ChocolArm64/Instruction/ASoftFallback.cs @@ -1,6 +1,5 @@ using ChocolArm64.Translation; using System; -using System.Numerics; namespace ChocolArm64.Instruction { diff --git a/Ryujinx.Graphics/Gal/GalConsts.cs b/Ryujinx.Graphics/Gal/GalConsts.cs deleted file mode 100644 index 6c8857c6e..000000000 --- a/Ryujinx.Graphics/Gal/GalConsts.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Ryujinx.Graphics.Gal -{ - public static class GalConsts - { - public const string FlipUniformName = "flip"; - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalBlend.cs b/Ryujinx.Graphics/Gal/IGalBlend.cs new file mode 100644 index 000000000..5c96a4923 --- /dev/null +++ b/Ryujinx.Graphics/Gal/IGalBlend.cs @@ -0,0 +1,22 @@ +namespace Ryujinx.Graphics.Gal +{ + public interface IGalBlend + { + void Enable(); + + void Disable(); + + void Set( + GalBlendEquation Equation, + GalBlendFactor FuncSrc, + GalBlendFactor FuncDst); + + void SetSeparate( + GalBlendEquation EquationRgb, + GalBlendEquation EquationAlpha, + GalBlendFactor FuncSrcRgb, + GalBlendFactor FuncDstRgb, + GalBlendFactor FuncSrcAlpha, + GalBlendFactor FuncDstAlpha); + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs new file mode 100644 index 000000000..eaae0a492 --- /dev/null +++ b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs @@ -0,0 +1,27 @@ +using System; + +namespace Ryujinx.Graphics.Gal +{ + public interface IGalFrameBuffer + { + void Create(long Key, int Width, int Height); + + void Bind(long Key); + + void BindTexture(long Key, int Index); + + void Set(long Key); + + void Set(byte[] Data, int Width, int Height); + + void SetTransform(float SX, float SY, float Rotate, float TX, float TY); + + void SetWindowSize(int Width, int Height); + + void SetViewport(int X, int Y, int Width, int Height); + + void Render(); + + void GetBufferData(long Key, Action Callback); + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalRasterizer.cs b/Ryujinx.Graphics/Gal/IGalRasterizer.cs new file mode 100644 index 000000000..81c922bef --- /dev/null +++ b/Ryujinx.Graphics/Gal/IGalRasterizer.cs @@ -0,0 +1,23 @@ +namespace Ryujinx.Graphics.Gal +{ + public interface IGalRasterizer + { + void ClearBuffers(int RtIndex, GalClearBufferFlags Flags); + + bool IsVboCached(long Key, long DataSize); + + bool IsIboCached(long Key, long DataSize); + + void CreateVbo(long Key, byte[] Buffer); + + void CreateIbo(long Key, byte[] Buffer); + + void SetVertexArray(int VbIndex, int Stride, long VboKey, GalVertexAttrib[] Attribs); + + void SetIndexArray(long Key, int Size, GalIndexFormat Format); + + void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType); + + void DrawElements(long IboKey, int First, GalPrimitiveType PrimType); + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs index b8f83469b..c6324c4a3 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderer.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs @@ -1,90 +1,21 @@ using System; -using System.Collections.Generic; namespace Ryujinx.Graphics.Gal { - public unsafe interface IGalRenderer + public interface IGalRenderer { void QueueAction(Action ActionMthd); void RunActions(); - void Render(); + IGalBlend Blend { get; } - void SetWindowSize(int Width, int Height); + IGalFrameBuffer FrameBuffer { get; } - //Blend - void SetBlendEnable(bool Enable); + IGalRasterizer Rasterizer { get; } - void SetBlend( - GalBlendEquation Equation, - GalBlendFactor FuncSrc, - GalBlendFactor FuncDst); + IGalShader Shader { get; } - void SetBlendSeparate( - GalBlendEquation EquationRgb, - GalBlendEquation EquationAlpha, - GalBlendFactor FuncSrcRgb, - GalBlendFactor FuncDstRgb, - GalBlendFactor FuncSrcAlpha, - GalBlendFactor FuncDstAlpha); - - //Frame Buffer - void CreateFrameBuffer(long Tag, int Width, int Height); - - void BindFrameBuffer(long Tag); - - void BindFrameBufferTexture(long Tag, int Index, GalTextureSampler Sampler); - - void SetFrameBuffer(long Tag); - - void SetFrameBuffer(byte[] Data, int Width, int Height); - - void SetFrameBufferTransform(float SX, float SY, float Rotate, float TX, float TY); - - void SetViewport(int X, int Y, int Width, int Height); - - void GetFrameBufferData(long Tag, Action Callback); - - //Rasterizer - void ClearBuffers(int RtIndex, GalClearBufferFlags Flags); - - bool IsVboCached(long Tag, long DataSize); - - bool IsIboCached(long Tag, long DataSize); - - void CreateVbo(long Tag, byte[] Buffer); - - void CreateIbo(long Tag, byte[] Buffer); - - void SetVertexArray(int VbIndex, int Stride, long VboTag, GalVertexAttrib[] Attribs); - - void SetIndexArray(long Tag, int Size, GalIndexFormat Format); - - void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType); - - void DrawElements(long IboTag, int First, GalPrimitiveType PrimType); - - //Shader - void CreateShader(IGalMemory Memory, long Tag, GalShaderType Type); - - IEnumerable GetTextureUsage(long Tag); - - void SetConstBuffer(long Tag, int Cbuf, byte[] Data); - - void SetUniform1(string UniformName, int Value); - - void SetUniform2F(string UniformName, float X, float Y); - - void BindShader(long Tag); - - void BindProgram(); - - //Texture - void SetTextureAndSampler(long Tag, byte[] Data, GalTexture Texture, GalTextureSampler Sampler); - - bool TryGetCachedTexture(long Tag, long DataSize, out GalTexture Texture); - - void BindTexture(long Tag, int Index); + IGalTexture Texture { get; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalShader.cs b/Ryujinx.Graphics/Gal/IGalShader.cs new file mode 100644 index 000000000..79e77c0a4 --- /dev/null +++ b/Ryujinx.Graphics/Gal/IGalShader.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Gal +{ + public interface IGalShader + { + void Create(IGalMemory Memory, long Key, GalShaderType Type); + + IEnumerable GetTextureUsage(long Key); + + void SetConstBuffer(long Key, int Cbuf, byte[] Data); + + void EnsureTextureBinding(string UniformName, int Value); + + void SetFlip(float X, float Y); + + void Bind(long Key); + + void BindProgram(); + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalTexture.cs b/Ryujinx.Graphics/Gal/IGalTexture.cs new file mode 100644 index 000000000..6379e73af --- /dev/null +++ b/Ryujinx.Graphics/Gal/IGalTexture.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Graphics.Gal +{ + public interface IGalTexture + { + void Create(long Key, byte[] Data, GalTexture Texture); + + bool TryGetCachedTexture(long Key, long DataSize, out GalTexture Texture); + + void Bind(long Key, int Index); + + void SetSampler(GalTextureSampler Sampler); + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs index e33851e54..7175e3a0e 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs @@ -2,7 +2,7 @@ using OpenTK.Graphics.OpenGL; namespace Ryujinx.Graphics.Gal.OpenGL { - class OGLBlend + public class OGLBlend : IGalBlend { public void Enable() { diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs index 8f265f544..4d91ff97e 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; namespace Ryujinx.Graphics.Gal.OpenGL { - class OGLFrameBuffer + public class OGLFrameBuffer : IGalFrameBuffer { private struct Rect { @@ -16,9 +16,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL public Rect(int X, int Y, int Width, int Height) { - this.X = X; - this.Y = Y; - this.Width = Width; + this.X = X; + this.Y = Y; + this.Width = Width; this.Height = Height; } } @@ -76,14 +76,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL Shader = new ShaderProgram(); } - public void Create(long Tag, int Width, int Height) + public void Create(long Key, int Width, int Height) { //TODO: We should either use the original frame buffer size, //or just remove the Width/Height arguments. Width = Window.Width; Height = Window.Height; - if (Fbs.TryGetValue(Tag, out FrameBuffer Fb)) + if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) { if (Fb.Width != Width || Fb.Height != Height) @@ -127,12 +127,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.Viewport(0, 0, Width, Height); - Fbs.Add(Tag, Fb); + Fbs.Add(Key, Fb); } - public void Bind(long Tag) + public void Bind(long Key) { - if (Fbs.TryGetValue(Tag, out FrameBuffer Fb)) + if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) { GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fb.Handle); @@ -140,9 +140,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } - public void BindTexture(long Tag, int Index) + public void BindTexture(long Key, int Index) { - if (Fbs.TryGetValue(Tag, out FrameBuffer Fb)) + if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) { GL.ActiveTexture(TextureUnit.Texture0 + Index); @@ -150,9 +150,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } - public void Set(long Tag) + public void Set(long Key) { - if (Fbs.TryGetValue(Tag, out FrameBuffer Fb)) + if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) { CurrTexHandle = Fb.TexHandle; } @@ -185,10 +185,17 @@ namespace Ryujinx.Graphics.Gal.OpenGL CurrTexHandle = RawFbTexHandle; } - public void SetTransform(Matrix2 Transform, Vector2 Offs) + public void SetTransform(float SX, float SY, float Rotate, float TX, float TY) { EnsureInitialized(); + Matrix2 Transform; + + Transform = Matrix2.CreateScale(SX, SY); + Transform *= Matrix2.CreateRotation(Rotate); + + Vector2 Offs = new Vector2(TX, TY); + int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram); GL.UseProgram(Shader.Handle); @@ -270,9 +277,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } - public void GetBufferData(long Tag, Action Callback) + public void GetBufferData(long Key, Action Callback) { - if (Fbs.TryGetValue(Tag, out FrameBuffer Fb)) + if (Fbs.TryGetValue(Key, out FrameBuffer Fb)) { GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, Fb.Handle); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs index b63c8b358..bdf22b9c1 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; namespace Ryujinx.Graphics.Gal.OpenGL { - class OGLRasterizer + public class OGLRasterizer : IGalRasterizer { private static Dictionary AttribElements = new Dictionary() @@ -74,8 +74,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL { ClearBufferMask Mask = 0; - //OpenGL doesn't support clearing just a single color channel, - //so we can't just clear all channels... + //TODO: Use glColorMask to clear just the specified channels. if (Flags.HasFlag(GalClearBufferFlags.ColorRed) && Flags.HasFlag(GalClearBufferFlags.ColorGreen) && Flags.HasFlag(GalClearBufferFlags.ColorBlue) && @@ -97,45 +96,43 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.Clear(Mask); } - public bool IsVboCached(long Tag, long DataSize) + public bool IsVboCached(long Key, long DataSize) { - return VboCache.TryGetSize(Tag, out long Size) && Size == DataSize; + return VboCache.TryGetSize(Key, out long Size) && Size == DataSize; } - public bool IsIboCached(long Tag, long DataSize) + public bool IsIboCached(long Key, long DataSize) { - return IboCache.TryGetSize(Tag, out long Size) && Size == DataSize; + return IboCache.TryGetSize(Key, out long Size) && Size == DataSize; } - public void CreateVbo(long Tag, byte[] Buffer) + public void CreateVbo(long Key, byte[] Buffer) { int Handle = GL.GenBuffer(); - VboCache.AddOrUpdate(Tag, Handle, (uint)Buffer.Length); + VboCache.AddOrUpdate(Key, Handle, (uint)Buffer.Length); IntPtr Length = new IntPtr(Buffer.Length); GL.BindBuffer(BufferTarget.ArrayBuffer, Handle); GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw); - GL.BindBuffer(BufferTarget.ArrayBuffer, 0); } - public void CreateIbo(long Tag, byte[] Buffer) + public void CreateIbo(long Key, byte[] Buffer) { int Handle = GL.GenBuffer(); - IboCache.AddOrUpdate(Tag, Handle, (uint)Buffer.Length); + IboCache.AddOrUpdate(Key, Handle, (uint)Buffer.Length); IntPtr Length = new IntPtr(Buffer.Length); GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle); GL.BufferData(BufferTarget.ElementArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw); - GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); } - public void SetVertexArray(int VbIndex, int Stride, long VboTag, GalVertexAttrib[] Attribs) + public void SetVertexArray(int VbIndex, int Stride, long VboKey, GalVertexAttrib[] Attribs) { - if (!VboCache.TryGetValue(VboTag, out int VboHandle)) + if (!VboCache.TryGetValue(VboKey, out int VboHandle)) { return; } @@ -178,11 +175,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Stride, Offset); } - - GL.BindVertexArray(0); } - public void SetIndexArray(long Tag, int Size, GalIndexFormat Format) + public void SetIndexArray(long Key, int Size, GalIndexFormat Format) { IndexBuffer.Type = OGLEnumConverter.GetDrawElementsType(Format); @@ -201,9 +196,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, PrimCount); } - public void DrawElements(long IboTag, int First, GalPrimitiveType PrimType) + public void DrawElements(long IboKey, int First, GalPrimitiveType PrimType) { - if (!IboCache.TryGetValue(IboTag, out int IboHandle)) + if (!IboCache.TryGetValue(IboKey, out int IboHandle)) { return; } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs new file mode 100644 index 000000000..ca70d4f66 --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Concurrent; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + public class OGLRenderer : IGalRenderer + { + public IGalBlend Blend { get; private set; } + + public IGalFrameBuffer FrameBuffer { get; private set; } + + public IGalRasterizer Rasterizer { get; private set; } + + public IGalShader Shader { get; private set; } + + public IGalTexture Texture { get; private set; } + + private ConcurrentQueue ActionsQueue; + + public OGLRenderer() + { + Blend = new OGLBlend(); + + FrameBuffer = new OGLFrameBuffer(); + + Rasterizer = new OGLRasterizer(); + + Shader = new OGLShader(); + + Texture = new OGLTexture(); + + ActionsQueue = new ConcurrentQueue(); + } + + public void QueueAction(Action ActionMthd) + { + ActionsQueue.Enqueue(ActionMthd); + } + + public void RunActions() + { + int Count = ActionsQueue.Count; + + while (Count-- > 0 && ActionsQueue.TryDequeue(out Action RenderAction)) + { + RenderAction(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs index be1bb20b4..5760d172a 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs @@ -7,7 +7,7 @@ using System.Linq; namespace Ryujinx.Graphics.Gal.OpenGL { - class OGLShader + public class OGLShader : IGalShader { private class ShaderStage : IDisposable { @@ -84,9 +84,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL Programs = new Dictionary(); } - public void Create(IGalMemory Memory, long Tag, GalShaderType Type) + public void Create(IGalMemory Memory, long Key, GalShaderType Type) { - Stages.GetOrAdd(Tag, (Key) => ShaderStageFactory(Memory, Tag, Type)); + Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, Key, Type)); } private ShaderStage ShaderStageFactory(IGalMemory Memory, long Position, GalShaderType Type) @@ -107,9 +107,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL return Decompiler.Decompile(Memory, Position + 0x50, Type); } - public IEnumerable GetTextureUsage(long Tag) + public IEnumerable GetTextureUsage(long Key) { - if (Stages.TryGetValue(Tag, out ShaderStage Stage)) + if (Stages.TryGetValue(Key, out ShaderStage Stage)) { return Stage.TextureUsage; } @@ -117,11 +117,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL return Enumerable.Empty(); } - public void SetConstBuffer(long Tag, int Cbuf, byte[] Data) + public void SetConstBuffer(long Key, int Cbuf, byte[] Data) { BindProgram(); - if (Stages.TryGetValue(Tag, out ShaderStage Stage)) + if (Stages.TryGetValue(Key, out ShaderStage Stage)) { foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage.Where(x => x.Cbuf == Cbuf)) { @@ -144,7 +144,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } - public void SetUniform1(string UniformName, int Value) + public void EnsureTextureBinding(string UniformName, int Value) { BindProgram(); @@ -153,18 +153,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.Uniform1(Location, Value); } - public void SetUniform2F(string UniformName, float X, float Y) + public void SetFlip(float X, float Y) { BindProgram(); - int Location = GL.GetUniformLocation(CurrentProgramHandle, UniformName); + int Location = GL.GetUniformLocation(CurrentProgramHandle, GlslDecl.FlipUniformName); GL.Uniform2(Location, X, Y); } - public void Bind(long Tag) + public void Bind(long Key) { - if (Stages.TryGetValue(Tag, out ShaderStage Stage)) + if (Stages.TryGetValue(Key, out ShaderStage Stage)) { Bind(Stage); } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs index 56f157e57..c50bdd71b 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs @@ -4,7 +4,7 @@ using System; namespace Ryujinx.Graphics.Gal.OpenGL { - class OGLTexture + public class OGLTexture : IGalTexture { private class TCE { @@ -31,11 +31,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.DeleteTexture(CachedTexture.Handle); } - public void Create(long Tag, byte[] Data, GalTexture Texture) + public void Create(long Key, byte[] Data, GalTexture Texture) { int Handle = GL.GenTexture(); - TextureCache.AddOrUpdate(Tag, new TCE(Handle, Texture), (uint)Data.Length); + TextureCache.AddOrUpdate(Key, new TCE(Handle, Texture), (uint)Data.Length); GL.BindTexture(TextureTarget.Texture2D, Handle); @@ -146,11 +146,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL throw new ArgumentException(nameof(Format)); } - public bool TryGetCachedTexture(long Tag, long DataSize, out GalTexture Texture) + public bool TryGetCachedTexture(long Key, long DataSize, out GalTexture Texture) { - if (TextureCache.TryGetSize(Tag, out long Size) && Size == DataSize) + if (TextureCache.TryGetSize(Key, out long Size) && Size == DataSize) { - if (TextureCache.TryGetValue(Tag, out TCE CachedTexture)) + if (TextureCache.TryGetValue(Key, out TCE CachedTexture)) { Texture = CachedTexture.Texture; @@ -163,9 +163,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL return false; } - public void Bind(long Tag, int Index) + public void Bind(long Key, int Index) { - if (TextureCache.TryGetValue(Tag, out TCE CachedTexture)) + if (TextureCache.TryGetValue(Key, out TCE CachedTexture)) { GL.ActiveTexture(TextureUnit.Texture0 + Index); @@ -173,7 +173,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } - public static void Set(GalTextureSampler Sampler) + public void SetSampler(GalTextureSampler Sampler) { int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU); int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs deleted file mode 100644 index 4c4bd2cae..000000000 --- a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs +++ /dev/null @@ -1,284 +0,0 @@ -using OpenTK; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; - -namespace Ryujinx.Graphics.Gal.OpenGL -{ - public class OpenGLRenderer : IGalRenderer - { - private OGLBlend Blend; - - private OGLFrameBuffer FrameBuffer; - - private OGLRasterizer Rasterizer; - - private OGLShader Shader; - - private OGLTexture Texture; - - private ConcurrentQueue ActionsQueue; - - public OpenGLRenderer() - { - Blend = new OGLBlend(); - - FrameBuffer = new OGLFrameBuffer(); - - Rasterizer = new OGLRasterizer(); - - Shader = new OGLShader(); - - Texture = new OGLTexture(); - - ActionsQueue = new ConcurrentQueue(); - } - - public void QueueAction(Action ActionMthd) - { - ActionsQueue.Enqueue(ActionMthd); - } - - public void RunActions() - { - int Count = ActionsQueue.Count; - - while (Count-- > 0 && ActionsQueue.TryDequeue(out Action RenderAction)) - { - RenderAction(); - } - } - - public void Render() - { - FrameBuffer.Render(); - } - - public void SetWindowSize(int Width, int Height) - { - FrameBuffer.SetWindowSize(Width, Height); - } - - public void SetBlendEnable(bool Enable) - { - if (Enable) - { - ActionsQueue.Enqueue(() => Blend.Enable()); - } - else - { - ActionsQueue.Enqueue(() => Blend.Disable()); - } - } - - public void SetBlend( - GalBlendEquation Equation, - GalBlendFactor FuncSrc, - GalBlendFactor FuncDst) - { - ActionsQueue.Enqueue(() => Blend.Set(Equation, FuncSrc, FuncDst)); - } - - public void SetBlendSeparate( - GalBlendEquation EquationRgb, - GalBlendEquation EquationAlpha, - GalBlendFactor FuncSrcRgb, - GalBlendFactor FuncDstRgb, - GalBlendFactor FuncSrcAlpha, - GalBlendFactor FuncDstAlpha) - { - ActionsQueue.Enqueue(() => - { - Blend.SetSeparate( - EquationRgb, - EquationAlpha, - FuncSrcRgb, - FuncDstRgb, - FuncSrcAlpha, - FuncDstAlpha); - }); - } - - public void CreateFrameBuffer(long Tag, int Width, int Height) - { - ActionsQueue.Enqueue(() => FrameBuffer.Create(Tag, Width, Height)); - } - - public void BindFrameBuffer(long Tag) - { - ActionsQueue.Enqueue(() => FrameBuffer.Bind(Tag)); - } - - public void BindFrameBufferTexture(long Tag, int Index, GalTextureSampler Sampler) - { - ActionsQueue.Enqueue(() => - { - FrameBuffer.BindTexture(Tag, Index); - - OGLTexture.Set(Sampler); - }); - } - - public void SetFrameBuffer(long Tag) - { - ActionsQueue.Enqueue(() => FrameBuffer.Set(Tag)); - } - - public void SetFrameBuffer(byte[] Data, int Width, int Height) - { - ActionsQueue.Enqueue(() => FrameBuffer.Set(Data, Width, Height)); - } - - public void SetFrameBufferTransform(float SX, float SY, float Rotate, float TX, float TY) - { - Matrix2 Transform; - - Transform = Matrix2.CreateScale(SX, SY); - Transform *= Matrix2.CreateRotation(Rotate); - - Vector2 Offs = new Vector2(TX, TY); - - ActionsQueue.Enqueue(() => FrameBuffer.SetTransform(Transform, Offs)); - } - - public void SetViewport(int X, int Y, int Width, int Height) - { - ActionsQueue.Enqueue(() => FrameBuffer.SetViewport(X, Y, Width, Height)); - } - - public void GetFrameBufferData(long Tag, Action Callback) - { - ActionsQueue.Enqueue(() => FrameBuffer.GetBufferData(Tag, Callback)); - } - - public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags) - { - ActionsQueue.Enqueue(() => Rasterizer.ClearBuffers(RtIndex, Flags)); - } - - public bool IsVboCached(long Tag, long DataSize) - { - return Rasterizer.IsVboCached(Tag, DataSize); - } - - public bool IsIboCached(long Tag, long DataSize) - { - return Rasterizer.IsIboCached(Tag, DataSize); - } - - public void CreateVbo(long Tag, byte[] Buffer) - { - ActionsQueue.Enqueue(() => Rasterizer.CreateVbo(Tag, Buffer)); - } - - public void CreateIbo(long Tag, byte[] Buffer) - { - ActionsQueue.Enqueue(() => Rasterizer.CreateIbo(Tag, Buffer)); - } - - public void SetVertexArray(int VbIndex, int Stride, long VboTag, GalVertexAttrib[] Attribs) - { - if ((uint)VbIndex > 31) - { - throw new ArgumentOutOfRangeException(nameof(VbIndex)); - } - - if (Attribs == null) - { - throw new ArgumentNullException(nameof(Attribs)); - } - - ActionsQueue.Enqueue(() => Rasterizer.SetVertexArray(VbIndex, Stride, VboTag, Attribs)); - } - - public void SetIndexArray(long Tag, int Size, GalIndexFormat Format) - { - ActionsQueue.Enqueue(() => Rasterizer.SetIndexArray(Tag, Size, Format)); - } - - public void DrawArrays(int First, int PrimCount, GalPrimitiveType PrimType) - { - ActionsQueue.Enqueue(() => Rasterizer.DrawArrays(First, PrimCount, PrimType)); - } - - public void DrawElements(long IboTag, int First, GalPrimitiveType PrimType) - { - ActionsQueue.Enqueue(() => Rasterizer.DrawElements(IboTag, First, PrimType)); - } - - public void CreateShader(IGalMemory Memory, long Tag, GalShaderType Type) - { - if (Memory == null) - { - throw new ArgumentNullException(nameof(Memory)); - } - - Shader.Create(Memory, Tag, Type); - } - - public void SetConstBuffer(long Tag, int Cbuf, byte[] Data) - { - if (Data == null) - { - throw new ArgumentNullException(nameof(Data)); - } - - ActionsQueue.Enqueue(() => Shader.SetConstBuffer(Tag, Cbuf, Data)); - } - - public void SetUniform1(string UniformName, int Value) - { - if (UniformName == null) - { - throw new ArgumentNullException(nameof(UniformName)); - } - - ActionsQueue.Enqueue(() => Shader.SetUniform1(UniformName, Value)); - } - - public void SetUniform2F(string UniformName, float X, float Y) - { - if (UniformName == null) - { - throw new ArgumentNullException(nameof(UniformName)); - } - - ActionsQueue.Enqueue(() => Shader.SetUniform2F(UniformName, X, Y)); - } - - public IEnumerable GetTextureUsage(long Tag) - { - return Shader.GetTextureUsage(Tag); - } - - public void BindShader(long Tag) - { - ActionsQueue.Enqueue(() => Shader.Bind(Tag)); - } - - public void BindProgram() - { - ActionsQueue.Enqueue(() => Shader.BindProgram()); - } - - public void SetTextureAndSampler(long Tag, byte[] Data, GalTexture Texture, GalTextureSampler Sampler) - { - ActionsQueue.Enqueue(() => - { - this.Texture.Create(Tag, Data, Texture); - - OGLTexture.Set(Sampler); - }); - } - - public bool TryGetCachedTexture(long Tag, long DataSize, out GalTexture Texture) - { - return this.Texture.TryGetCachedTexture(Tag, DataSize, out Texture); - } - - public void BindTexture(long Tag, int Index) - { - ActionsQueue.Enqueue(() => Texture.Bind(Tag, Index)); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs index 4002c29a5..86838ab2e 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs @@ -26,6 +26,8 @@ namespace Ryujinx.Graphics.Gal.Shader public const string FragmentOutputName = "FragColor"; + public const string FlipUniformName = "flip"; + private string[] StagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" }; private string StagePrefix; diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index 77f16b81f..24db303f2 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.Gal.Shader { if (Decl.ShaderType == GalShaderType.Vertex) { - SB.AppendLine("uniform vec2 " + GalConsts.FlipUniformName + ";"); + SB.AppendLine("uniform vec2 " + GlslDecl.FlipUniformName + ";"); } foreach (ShaderDeclInfo DeclInfo in Decl.Uniforms.Values.OrderBy(DeclKeySelector)) diff --git a/Ryujinx.HLE/Gpu/INvGpuEngine.cs b/Ryujinx.HLE/Gpu/Engines/INvGpuEngine.cs similarity index 67% rename from Ryujinx.HLE/Gpu/INvGpuEngine.cs rename to Ryujinx.HLE/Gpu/Engines/INvGpuEngine.cs index 62307f582..068878a98 100644 --- a/Ryujinx.HLE/Gpu/INvGpuEngine.cs +++ b/Ryujinx.HLE/Gpu/Engines/INvGpuEngine.cs @@ -1,4 +1,6 @@ -namespace Ryujinx.HLE.Gpu +using Ryujinx.HLE.Gpu.Memory; + +namespace Ryujinx.HLE.Gpu.Engines { interface INvGpuEngine { diff --git a/Ryujinx.HLE/Gpu/MacroInterpreter.cs b/Ryujinx.HLE/Gpu/Engines/MacroInterpreter.cs similarity index 94% rename from Ryujinx.HLE/Gpu/MacroInterpreter.cs rename to Ryujinx.HLE/Gpu/Engines/MacroInterpreter.cs index c333046a9..aef2eb4c8 100644 --- a/Ryujinx.HLE/Gpu/MacroInterpreter.cs +++ b/Ryujinx.HLE/Gpu/Engines/MacroInterpreter.cs @@ -1,10 +1,16 @@ +using Ryujinx.HLE.Gpu.Exceptions; +using Ryujinx.HLE.Gpu.Memory; using System; using System.Collections.Generic; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Engines { class MacroInterpreter { + private const int MaxCallCountPerRun = 500; + + private int CallCount; + private enum AssignmentOperation { IgnoreAndFetch = 0, @@ -96,6 +102,8 @@ namespace Ryujinx.HLE.Gpu MethIncr = 0; Carry = false; + + CallCount = 0; } private bool Step(NvGpuVmm Vmm, int[] Mme) @@ -407,6 +415,15 @@ namespace Ryujinx.HLE.Gpu private void Send(NvGpuVmm Vmm, int Value) { + //This is an artificial limit that prevents excessive calls + //to VertexEndGl since that triggers rendering, and in the + //case that something is bugged and causes an absurd amount of + //draw calls, this prevents the system from freezing (and throws instead). + if (MethAddr == 0x585 && ++CallCount > MaxCallCountPerRun) + { + GpuExceptionHelper.ThrowCallCoundExceeded(); + } + NvGpuPBEntry PBEntry = new NvGpuPBEntry(MethAddr, 0, Value); Engine.CallMethod(Vmm, PBEntry); diff --git a/Ryujinx.HLE/Gpu/NvGpuEngine.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine.cs similarity index 82% rename from Ryujinx.HLE/Gpu/NvGpuEngine.cs rename to Ryujinx.HLE/Gpu/Engines/NvGpuEngine.cs index 41697ed69..f9d6342cf 100644 --- a/Ryujinx.HLE/Gpu/NvGpuEngine.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Engines { enum NvGpuEngine { diff --git a/Ryujinx.HLE/Gpu/NvGpuEngine2d.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine2d.cs similarity index 90% rename from Ryujinx.HLE/Gpu/NvGpuEngine2d.cs rename to Ryujinx.HLE/Gpu/Engines/NvGpuEngine2d.cs index 15667eeb2..f150b3f5e 100644 --- a/Ryujinx.HLE/Gpu/NvGpuEngine2d.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine2d.cs @@ -1,7 +1,9 @@ using Ryujinx.Graphics.Gal; +using Ryujinx.HLE.Gpu.Memory; +using Ryujinx.HLE.Gpu.Texture; using System.Collections.Generic; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Engines { class NvGpuEngine2d : INvGpuEngine { @@ -75,19 +77,19 @@ namespace Ryujinx.HLE.Gpu int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf); - long Tag = Vmm.GetPhysicalAddress(MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress)); + long Key = Vmm.GetPhysicalAddress(MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress)); long SrcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress); long DstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress); - bool IsFbTexture = Gpu.Engine3d.IsFrameBufferPosition(Tag); + bool IsFbTexture = Gpu.Engine3d.IsFrameBufferPosition(Key); if (IsFbTexture && DstLinear) { DstSwizzle = TextureSwizzle.BlockLinear; } - Texture DstTexture = new Texture( + TextureInfo DstTexture = new TextureInfo( DstAddress, DstWidth, DstHeight, @@ -103,7 +105,7 @@ namespace Ryujinx.HLE.Gpu SrcWidth = 1280; SrcHeight = 720; - Gpu.Renderer.GetFrameBufferData(Tag, (byte[] Buffer) => + Gpu.Renderer.FrameBuffer.GetBufferData(Key, (byte[] Buffer) => { CopyTexture( Vmm, @@ -129,11 +131,11 @@ namespace Ryujinx.HLE.Gpu } private void CopyTexture( - NvGpuVmm Vmm, - Texture Texture, - byte[] Buffer, - int Width, - int Height) + NvGpuVmm Vmm, + TextureInfo Texture, + byte[] Buffer, + int Width, + int Height) { TextureWriter.Write(Vmm, Texture, Buffer, Width, Height); } diff --git a/Ryujinx.HLE/Gpu/NvGpuEngine2dReg.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine2dReg.cs similarity index 95% rename from Ryujinx.HLE/Gpu/NvGpuEngine2dReg.cs rename to Ryujinx.HLE/Gpu/Engines/NvGpuEngine2dReg.cs index 1039e3680..29d66d463 100644 --- a/Ryujinx.HLE/Gpu/NvGpuEngine2dReg.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine2dReg.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Engines { enum NvGpuEngine2dReg { diff --git a/Ryujinx.HLE/Gpu/NvGpuEngine3d.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs similarity index 82% rename from Ryujinx.HLE/Gpu/NvGpuEngine3d.cs rename to Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs index 6d03e6b89..02461d5dd 100644 --- a/Ryujinx.HLE/Gpu/NvGpuEngine3d.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs @@ -1,8 +1,10 @@ using Ryujinx.Graphics.Gal; +using Ryujinx.HLE.Gpu.Memory; +using Ryujinx.HLE.Gpu.Texture; using System; using System.Collections.Generic; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Engines { class NvGpuEngine3d : INvGpuEngine { @@ -73,13 +75,13 @@ namespace Ryujinx.HLE.Gpu { SetFrameBuffer(Vmm, 0); - long[] Tags = UploadShaders(Vmm); + long[] Keys = UploadShaders(Vmm); - Gpu.Renderer.BindProgram(); + Gpu.Renderer.Shader.BindProgram(); SetAlphaBlending(); - UploadTextures(Vmm, Tags); + UploadTextures(Vmm, Keys); UploadUniforms(Vmm); UploadVertexArrays(Vmm); } @@ -113,13 +115,13 @@ namespace Ryujinx.HLE.Gpu //Note: Using the Width/Height results seems to give incorrect results. //Maybe the size of all frame buffers is hardcoded to screen size? This seems unlikely. - Gpu.Renderer.CreateFrameBuffer(PA, 1280, 720); - Gpu.Renderer.BindFrameBuffer(PA); + Gpu.Renderer.FrameBuffer.Create(PA, 1280, 720); + Gpu.Renderer.FrameBuffer.Bind(PA); } private long[] UploadShaders(NvGpuVmm Vmm) { - long[] Tags = new long[5]; + long[] Keys = new long[5]; long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); @@ -136,14 +138,14 @@ namespace Ryujinx.HLE.Gpu continue; } - long Tag = BasePosition + (uint)Offset; + long Key = BasePosition + (uint)Offset; GalShaderType ShaderType = GetTypeFromProgram(Index); - Tags[(int)ShaderType] = Tag; + Keys[(int)ShaderType] = Key; - Gpu.Renderer.CreateShader(Vmm, Tag, ShaderType); - Gpu.Renderer.BindShader(Tag); + Gpu.Renderer.Shader.Create(Vmm, Key, ShaderType); + Gpu.Renderer.Shader.Bind(Key); } int RawSX = ReadRegister(NvGpuEngine3dReg.ViewportScaleX); @@ -155,9 +157,9 @@ namespace Ryujinx.HLE.Gpu float SignX = MathF.Sign(SX); float SignY = MathF.Sign(SY); - Gpu.Renderer.SetUniform2F(GalConsts.FlipUniformName, SignX, SignY); + Gpu.Renderer.Shader.SetFlip(SignX, SignY); - return Tags; + return Keys; } private static GalShaderType GetTypeFromProgram(int Program) @@ -180,7 +182,14 @@ namespace Ryujinx.HLE.Gpu //TODO: Support independent blend properly. bool Enable = (ReadRegister(NvGpuEngine3dReg.IBlendNEnable) & 1) != 0; - Gpu.Renderer.SetBlendEnable(Enable); + if (Enable) + { + Gpu.Renderer.Blend.Enable(); + } + else + { + Gpu.Renderer.Blend.Disable(); + } if (!Enable) { @@ -203,7 +212,7 @@ namespace Ryujinx.HLE.Gpu GalBlendFactor FuncSrcAlpha = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncSrcAlpha); GalBlendFactor FuncDstAlpha = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncDstAlpha); - Gpu.Renderer.SetBlendSeparate( + Gpu.Renderer.Blend.SetSeparate( EquationRgb, EquationAlpha, FuncSrcRgb, @@ -213,11 +222,11 @@ namespace Ryujinx.HLE.Gpu } else { - Gpu.Renderer.SetBlend(EquationRgb, FuncSrcRgb, FuncDstRgb); + Gpu.Renderer.Blend.Set(EquationRgb, FuncSrcRgb, FuncDstRgb); } } - private void UploadTextures(NvGpuVmm Vmm, long[] Tags) + private void UploadTextures(NvGpuVmm Vmm, long[] Keys) { long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); @@ -227,15 +236,15 @@ namespace Ryujinx.HLE.Gpu //reserved for drawing the frame buffer. int TexIndex = 1; - for (int Index = 0; Index < Tags.Length; Index++) + for (int Index = 0; Index < Keys.Length; Index++) { - foreach (ShaderDeclInfo DeclInfo in Gpu.Renderer.GetTextureUsage(Tags[Index])) + foreach (ShaderDeclInfo DeclInfo in Gpu.Renderer.Shader.GetTextureUsage(Keys[Index])) { long Position = ConstBuffers[Index][TextureCbIndex].Position; UploadTexture(Vmm, Position, TexIndex, DeclInfo.Index); - Gpu.Renderer.SetUniform1(DeclInfo.Name, TexIndex); + Gpu.Renderer.Shader.EnsureTextureBinding(DeclInfo.Name, TexIndex); TexIndex++; } @@ -270,7 +279,7 @@ namespace Ryujinx.HLE.Gpu long TextureAddress = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff; - long Tag = TextureAddress; + long Key = TextureAddress; TextureAddress = Vmm.GetPhysicalAddress(TextureAddress); @@ -280,7 +289,7 @@ namespace Ryujinx.HLE.Gpu //we shouldn't read anything from memory and bind //the frame buffer texture instead, since we're not //really writing anything to memory. - Gpu.Renderer.BindFrameBufferTexture(TextureAddress, TexIndex, Sampler); + Gpu.Renderer.FrameBuffer.BindTexture(TextureAddress, TexIndex); } else { @@ -288,22 +297,29 @@ namespace Ryujinx.HLE.Gpu long Size = (uint)TextureHelper.GetTextureSize(NewTexture); - if (Gpu.Renderer.TryGetCachedTexture(Tag, Size, out GalTexture Texture)) - { - if (NewTexture.Equals(Texture) && !Vmm.IsRegionModified(Tag, Size, NvGpuBufferType.Texture)) - { - Gpu.Renderer.BindTexture(Tag, TexIndex); + bool HasCachedTexture = false; - return; + if (Gpu.Renderer.Texture.TryGetCachedTexture(Key, Size, out GalTexture Texture)) + { + if (NewTexture.Equals(Texture) && !Vmm.IsRegionModified(Key, Size, NvGpuBufferType.Texture)) + { + Gpu.Renderer.Texture.Bind(Key, TexIndex); + + HasCachedTexture = true; } } - byte[] Data = TextureFactory.GetTextureData(Vmm, TicPosition); + if (!HasCachedTexture) + { + byte[] Data = TextureFactory.GetTextureData(Vmm, TicPosition); - Gpu.Renderer.SetTextureAndSampler(Tag, Data, NewTexture, Sampler); + Gpu.Renderer.Texture.Create(Key, Data, NewTexture); + } - Gpu.Renderer.BindTexture(Tag, TexIndex); + Gpu.Renderer.Texture.Bind(Key, TexIndex); } + + Gpu.Renderer.Texture.SetSampler(Sampler); } private void UploadUniforms(NvGpuVmm Vmm) @@ -331,7 +347,7 @@ namespace Ryujinx.HLE.Gpu { byte[] Data = Vmm.ReadBytes(Cb.Position, (uint)Cb.Size); - Gpu.Renderer.SetConstBuffer(BasePosition + (uint)Offset, Cbuf, Data); + Gpu.Renderer.Shader.SetConstBuffer(BasePosition + (uint)Offset, Cbuf, Data); } } } @@ -341,33 +357,33 @@ namespace Ryujinx.HLE.Gpu { long IndexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress); - int IndexSize = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat); - int IndexFirst = ReadRegister(NvGpuEngine3dReg.IndexBatchFirst); - int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount); + int IndexEntryFmt = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat); + int IndexFirst = ReadRegister(NvGpuEngine3dReg.IndexBatchFirst); + int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount); - GalIndexFormat IndexFormat = (GalIndexFormat)IndexSize; + GalIndexFormat IndexFormat = (GalIndexFormat)IndexEntryFmt; - IndexSize = 1 << IndexSize; + int IndexEntrySize = 1 << IndexEntryFmt; - if (IndexSize > 4) + if (IndexEntrySize > 4) { throw new InvalidOperationException(); } if (IndexCount != 0) { - int IbSize = IndexCount * IndexSize; + int IbSize = IndexCount * IndexEntrySize; - bool IboCached = Gpu.Renderer.IsIboCached(IndexPosition, (uint)IbSize); + bool IboCached = Gpu.Renderer.Rasterizer.IsIboCached(IndexPosition, (uint)IbSize); if (!IboCached || Vmm.IsRegionModified(IndexPosition, (uint)IbSize, NvGpuBufferType.Index)) { byte[] Data = Vmm.ReadBytes(IndexPosition, (uint)IbSize); - Gpu.Renderer.CreateIbo(IndexPosition, Data); + Gpu.Renderer.Rasterizer.CreateIbo(IndexPosition, Data); } - Gpu.Renderer.SetIndexArray(IndexPosition, IbSize, IndexFormat); + Gpu.Renderer.Rasterizer.SetIndexArray(IndexPosition, IbSize, IndexFormat); } List[] Attribs = new List[32]; @@ -429,27 +445,27 @@ namespace Ryujinx.HLE.Gpu VbSize = VertexCount * Stride; } - bool VboCached = Gpu.Renderer.IsVboCached(VertexPosition, VbSize); + bool VboCached = Gpu.Renderer.Rasterizer.IsVboCached(VertexPosition, VbSize); if (!VboCached || Vmm.IsRegionModified(VertexPosition, VbSize, NvGpuBufferType.Vertex)) { byte[] Data = Vmm.ReadBytes(VertexPosition, VbSize); - Gpu.Renderer.CreateVbo(VertexPosition, Data); + Gpu.Renderer.Rasterizer.CreateVbo(VertexPosition, Data); } - Gpu.Renderer.SetVertexArray(Index, Stride, VertexPosition, Attribs[Index].ToArray()); + Gpu.Renderer.Rasterizer.SetVertexArray(Index, Stride, VertexPosition, Attribs[Index].ToArray()); } GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff); if (IndexCount != 0) { - Gpu.Renderer.DrawElements(IndexPosition, IndexFirst, PrimType); + Gpu.Renderer.Rasterizer.DrawElements(IndexPosition, IndexFirst, PrimType); } else { - Gpu.Renderer.DrawArrays(VertexFirst, VertexCount, PrimType); + Gpu.Renderer.Rasterizer.DrawArrays(VertexFirst, VertexCount, PrimType); } } diff --git a/Ryujinx.HLE/Gpu/NvGpuEngine3dReg.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs similarity index 98% rename from Ryujinx.HLE/Gpu/NvGpuEngine3dReg.cs rename to Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs index e0de4777d..de2b2eef2 100644 --- a/Ryujinx.HLE/Gpu/NvGpuEngine3dReg.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3dReg.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Engines { enum NvGpuEngine3dReg { diff --git a/Ryujinx.HLE/Gpu/NvGpuEngineDma.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngineDma.cs similarity index 97% rename from Ryujinx.HLE/Gpu/NvGpuEngineDma.cs rename to Ryujinx.HLE/Gpu/Engines/NvGpuEngineDma.cs index ed7819e96..7e355e8de 100644 --- a/Ryujinx.HLE/Gpu/NvGpuEngineDma.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngineDma.cs @@ -1,6 +1,8 @@ +using Ryujinx.HLE.Gpu.Memory; +using Ryujinx.HLE.Gpu.Texture; using System.Collections.Generic; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Engines { class NvGpuEngineDma : INvGpuEngine { diff --git a/Ryujinx.HLE/Gpu/NvGpuEngineDmaReg.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngineDmaReg.cs similarity index 93% rename from Ryujinx.HLE/Gpu/NvGpuEngineDmaReg.cs rename to Ryujinx.HLE/Gpu/Engines/NvGpuEngineDmaReg.cs index 55b404c5e..835a822d1 100644 --- a/Ryujinx.HLE/Gpu/NvGpuEngineDmaReg.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngineDmaReg.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Engines { enum NvGpuEngineDmaReg { diff --git a/Ryujinx.HLE/Gpu/NvGpuFifo.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuFifo.cs similarity index 98% rename from Ryujinx.HLE/Gpu/NvGpuFifo.cs rename to Ryujinx.HLE/Gpu/Engines/NvGpuFifo.cs index 361c8bcec..0bc682a70 100644 --- a/Ryujinx.HLE/Gpu/NvGpuFifo.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuFifo.cs @@ -1,6 +1,7 @@ +using Ryujinx.HLE.Gpu.Memory; using System.Collections.Concurrent; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Engines { class NvGpuFifo { diff --git a/Ryujinx.HLE/Gpu/NvGpuFifoMeth.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuFifoMeth.cs similarity index 86% rename from Ryujinx.HLE/Gpu/NvGpuFifoMeth.cs rename to Ryujinx.HLE/Gpu/Engines/NvGpuFifoMeth.cs index 247a7bfc4..ffd179f26 100644 --- a/Ryujinx.HLE/Gpu/NvGpuFifoMeth.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuFifoMeth.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Engines { enum NvGpuFifoMeth { diff --git a/Ryujinx.HLE/Gpu/NvGpuMethod.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuMethod.cs similarity index 51% rename from Ryujinx.HLE/Gpu/NvGpuMethod.cs rename to Ryujinx.HLE/Gpu/Engines/NvGpuMethod.cs index f7ff66475..04c92f2a9 100644 --- a/Ryujinx.HLE/Gpu/NvGpuMethod.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuMethod.cs @@ -1,4 +1,6 @@ -namespace Ryujinx.HLE.Gpu +using Ryujinx.HLE.Gpu.Memory; + +namespace Ryujinx.HLE.Gpu.Engines { delegate void NvGpuMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry); } \ No newline at end of file diff --git a/Ryujinx.HLE/Gpu/Exceptions/GpuException.cs b/Ryujinx.HLE/Gpu/Exceptions/GpuException.cs new file mode 100644 index 000000000..c0bce5a52 --- /dev/null +++ b/Ryujinx.HLE/Gpu/Exceptions/GpuException.cs @@ -0,0 +1,11 @@ +using System; + +namespace Ryujinx.HLE.Gpu.Exceptions +{ + class GpuException : Exception + { + public GpuException() : base() { } + + public GpuException(string ExMsg) : base(ExMsg) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Gpu/Exceptions/GpuExceptionHelper.cs b/Ryujinx.HLE/Gpu/Exceptions/GpuExceptionHelper.cs new file mode 100644 index 000000000..aeab9a291 --- /dev/null +++ b/Ryujinx.HLE/Gpu/Exceptions/GpuExceptionHelper.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.HLE.Gpu.Exceptions +{ + static class GpuExceptionHelper + { + private const string CallCountExceeded = "Method call count exceeded the limit allowed per run!"; + + public static void ThrowCallCoundExceeded() + { + throw new GpuException(CallCountExceeded); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Gpu/NvGpuBufferType.cs b/Ryujinx.HLE/Gpu/Memory/NvGpuBufferType.cs similarity index 72% rename from Ryujinx.HLE/Gpu/NvGpuBufferType.cs rename to Ryujinx.HLE/Gpu/Memory/NvGpuBufferType.cs index a44a772db..7474aa33f 100644 --- a/Ryujinx.HLE/Gpu/NvGpuBufferType.cs +++ b/Ryujinx.HLE/Gpu/Memory/NvGpuBufferType.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Memory { enum NvGpuBufferType { diff --git a/Ryujinx.HLE/Gpu/NvGpuPBEntry.cs b/Ryujinx.HLE/Gpu/Memory/NvGpuPBEntry.cs similarity index 94% rename from Ryujinx.HLE/Gpu/NvGpuPBEntry.cs rename to Ryujinx.HLE/Gpu/Memory/NvGpuPBEntry.cs index 2cd663fed..aba89e3c9 100644 --- a/Ryujinx.HLE/Gpu/NvGpuPBEntry.cs +++ b/Ryujinx.HLE/Gpu/Memory/NvGpuPBEntry.cs @@ -1,7 +1,7 @@ using System; using System.Collections.ObjectModel; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Memory { struct NvGpuPBEntry { diff --git a/Ryujinx.HLE/Gpu/NvGpuPushBuffer.cs b/Ryujinx.HLE/Gpu/Memory/NvGpuPushBuffer.cs similarity index 99% rename from Ryujinx.HLE/Gpu/NvGpuPushBuffer.cs rename to Ryujinx.HLE/Gpu/Memory/NvGpuPushBuffer.cs index 2d4f0c1ac..6121b3e61 100644 --- a/Ryujinx.HLE/Gpu/NvGpuPushBuffer.cs +++ b/Ryujinx.HLE/Gpu/Memory/NvGpuPushBuffer.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.IO; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Memory { static class NvGpuPushBuffer { diff --git a/Ryujinx.HLE/Gpu/NvGpuVmm.cs b/Ryujinx.HLE/Gpu/Memory/NvGpuVmm.cs similarity index 99% rename from Ryujinx.HLE/Gpu/NvGpuVmm.cs rename to Ryujinx.HLE/Gpu/Memory/NvGpuVmm.cs index b0ba3e90b..36f6406a1 100644 --- a/Ryujinx.HLE/Gpu/NvGpuVmm.cs +++ b/Ryujinx.HLE/Gpu/Memory/NvGpuVmm.cs @@ -2,7 +2,7 @@ using ChocolArm64.Memory; using Ryujinx.Graphics.Gal; using System.Collections.Concurrent; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Memory { class NvGpuVmm : IAMemory, IGalMemory { diff --git a/Ryujinx.HLE/Gpu/NvGpuVmmCache.cs b/Ryujinx.HLE/Gpu/Memory/NvGpuVmmCache.cs similarity index 99% rename from Ryujinx.HLE/Gpu/NvGpuVmmCache.cs rename to Ryujinx.HLE/Gpu/Memory/NvGpuVmmCache.cs index 38b25e4fc..c7108f00c 100644 --- a/Ryujinx.HLE/Gpu/NvGpuVmmCache.cs +++ b/Ryujinx.HLE/Gpu/Memory/NvGpuVmmCache.cs @@ -2,7 +2,7 @@ using ChocolArm64.Memory; using System; using System.Collections.Generic; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Memory { class NvGpuVmmCache { diff --git a/Ryujinx.HLE/Gpu/NvGpu.cs b/Ryujinx.HLE/Gpu/NvGpu.cs index 0301fcf22..625cb727f 100644 --- a/Ryujinx.HLE/Gpu/NvGpu.cs +++ b/Ryujinx.HLE/Gpu/NvGpu.cs @@ -1,5 +1,5 @@ using Ryujinx.Graphics.Gal; -using System.Threading; +using Ryujinx.HLE.Gpu.Engines; namespace Ryujinx.HLE.Gpu { @@ -13,10 +13,6 @@ namespace Ryujinx.HLE.Gpu public NvGpuEngine3d Engine3d { get; private set; } public NvGpuEngineDma EngineDma { get; private set; } - private Thread FifoProcessing; - - private bool KeepRunning; - public NvGpu(IGalRenderer Renderer) { this.Renderer = Renderer; @@ -26,22 +22,6 @@ namespace Ryujinx.HLE.Gpu Engine2d = new NvGpuEngine2d(this); Engine3d = new NvGpuEngine3d(this); EngineDma = new NvGpuEngineDma(this); - - KeepRunning = true; - - FifoProcessing = new Thread(ProcessFifo); - - FifoProcessing.Start(); - } - - private void ProcessFifo() - { - while (KeepRunning) - { - Fifo.DispatchCalls(); - - Thread.Yield(); - } } } } \ No newline at end of file diff --git a/Ryujinx.HLE/Gpu/BlockLinearSwizzle.cs b/Ryujinx.HLE/Gpu/Texture/BlockLinearSwizzle.cs similarity index 97% rename from Ryujinx.HLE/Gpu/BlockLinearSwizzle.cs rename to Ryujinx.HLE/Gpu/Texture/BlockLinearSwizzle.cs index 366f57403..e66d76136 100644 --- a/Ryujinx.HLE/Gpu/BlockLinearSwizzle.cs +++ b/Ryujinx.HLE/Gpu/Texture/BlockLinearSwizzle.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Texture { class BlockLinearSwizzle : ISwizzle { diff --git a/Ryujinx.HLE/Gpu/ISwizzle.cs b/Ryujinx.HLE/Gpu/Texture/ISwizzle.cs similarity index 70% rename from Ryujinx.HLE/Gpu/ISwizzle.cs rename to Ryujinx.HLE/Gpu/Texture/ISwizzle.cs index 525707ba7..222aab163 100644 --- a/Ryujinx.HLE/Gpu/ISwizzle.cs +++ b/Ryujinx.HLE/Gpu/Texture/ISwizzle.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Texture { interface ISwizzle { diff --git a/Ryujinx.HLE/Gpu/LinearSwizzle.cs b/Ryujinx.HLE/Gpu/Texture/LinearSwizzle.cs similarity index 91% rename from Ryujinx.HLE/Gpu/LinearSwizzle.cs rename to Ryujinx.HLE/Gpu/Texture/LinearSwizzle.cs index 995866ad6..720f78322 100644 --- a/Ryujinx.HLE/Gpu/LinearSwizzle.cs +++ b/Ryujinx.HLE/Gpu/Texture/LinearSwizzle.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Texture { class LinearSwizzle : ISwizzle { diff --git a/Ryujinx.HLE/Gpu/TextureFactory.cs b/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs similarity index 96% rename from Ryujinx.HLE/Gpu/TextureFactory.cs rename to Ryujinx.HLE/Gpu/Texture/TextureFactory.cs index 94c6eb183..9df0b6000 100644 --- a/Ryujinx.HLE/Gpu/TextureFactory.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs @@ -1,7 +1,8 @@ using Ryujinx.Graphics.Gal; +using Ryujinx.HLE.Gpu.Memory; using System; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Texture { static class TextureFactory { @@ -61,7 +62,7 @@ namespace Ryujinx.HLE.Gpu int Width = (Tic[4] & 0xffff) + 1; int Height = (Tic[5] & 0xffff) + 1; - Texture Texture = new Texture( + TextureInfo Texture = new TextureInfo( TextureAddress, Width, Height, diff --git a/Ryujinx.HLE/Gpu/TextureHelper.cs b/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs similarity index 94% rename from Ryujinx.HLE/Gpu/TextureHelper.cs rename to Ryujinx.HLE/Gpu/Texture/TextureHelper.cs index 237d87abc..ac8f75c5f 100644 --- a/Ryujinx.HLE/Gpu/TextureHelper.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureHelper.cs @@ -1,12 +1,13 @@ using ChocolArm64.Memory; using Ryujinx.Graphics.Gal; +using Ryujinx.HLE.Gpu.Memory; using System; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Texture { static class TextureHelper { - public static ISwizzle GetSwizzle(Texture Texture, int Width, int Bpp) + public static ISwizzle GetSwizzle(TextureInfo Texture, int Width, int Bpp) { switch (Texture.Swizzle) { diff --git a/Ryujinx.HLE/Gpu/Texture.cs b/Ryujinx.HLE/Gpu/Texture/TextureInfo.cs similarity index 92% rename from Ryujinx.HLE/Gpu/Texture.cs rename to Ryujinx.HLE/Gpu/Texture/TextureInfo.cs index 1de7f302c..31784bbc5 100644 --- a/Ryujinx.HLE/Gpu/Texture.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureInfo.cs @@ -1,8 +1,8 @@ using Ryujinx.Graphics.Gal; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Texture { - struct Texture + struct TextureInfo { public long Position { get; private set; } @@ -16,7 +16,7 @@ namespace Ryujinx.HLE.Gpu public GalTextureFormat Format { get; private set; } - public Texture( + public TextureInfo( long Position, int Width, int Height) @@ -34,7 +34,7 @@ namespace Ryujinx.HLE.Gpu Format = GalTextureFormat.A8B8G8R8; } - public Texture( + public TextureInfo( long Position, int Width, int Height, diff --git a/Ryujinx.HLE/Gpu/TextureReader.cs b/Ryujinx.HLE/Gpu/Texture/TextureReader.cs similarity index 97% rename from Ryujinx.HLE/Gpu/TextureReader.cs rename to Ryujinx.HLE/Gpu/Texture/TextureReader.cs index 9e9ff7834..48bf1a90f 100644 --- a/Ryujinx.HLE/Gpu/TextureReader.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureReader.cs @@ -2,11 +2,11 @@ using ChocolArm64.Memory; using Ryujinx.Graphics.Gal; using System; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Texture { static class TextureReader { - public static byte[] Read(IAMemory Memory, Texture Texture) + public static byte[] Read(IAMemory Memory, TextureInfo Texture) { switch (Texture.Format) { @@ -31,7 +31,7 @@ namespace Ryujinx.HLE.Gpu throw new NotImplementedException(Texture.Format.ToString()); } - private unsafe static byte[] Read1Bpp(IAMemory Memory, Texture Texture) + private unsafe static byte[] Read1Bpp(IAMemory Memory, TextureInfo Texture) { int Width = Texture.Width; int Height = Texture.Height; @@ -64,7 +64,7 @@ namespace Ryujinx.HLE.Gpu return Output; } - private unsafe static byte[] Read5551(IAMemory Memory, Texture Texture) + private unsafe static byte[] Read5551(IAMemory Memory, TextureInfo Texture) { int Width = Texture.Width; int Height = Texture.Height; @@ -102,7 +102,7 @@ namespace Ryujinx.HLE.Gpu return Output; } - private unsafe static byte[] Read565(IAMemory Memory, Texture Texture) + private unsafe static byte[] Read565(IAMemory Memory, TextureInfo Texture) { int Width = Texture.Width; int Height = Texture.Height; @@ -139,7 +139,7 @@ namespace Ryujinx.HLE.Gpu return Output; } - private unsafe static byte[] Read2Bpp(IAMemory Memory, Texture Texture) + private unsafe static byte[] Read2Bpp(IAMemory Memory, TextureInfo Texture) { int Width = Texture.Width; int Height = Texture.Height; @@ -172,7 +172,7 @@ namespace Ryujinx.HLE.Gpu return Output; } - private unsafe static byte[] Read4Bpp(IAMemory Memory, Texture Texture) + private unsafe static byte[] Read4Bpp(IAMemory Memory, TextureInfo Texture) { int Width = Texture.Width; int Height = Texture.Height; @@ -205,7 +205,7 @@ namespace Ryujinx.HLE.Gpu return Output; } - private unsafe static byte[] Read8Bpp(IAMemory Memory, Texture Texture) + private unsafe static byte[] Read8Bpp(IAMemory Memory, TextureInfo Texture) { int Width = Texture.Width; int Height = Texture.Height; @@ -238,7 +238,7 @@ namespace Ryujinx.HLE.Gpu return Output; } - private unsafe static byte[] Read16Bpp(IAMemory Memory, Texture Texture) + private unsafe static byte[] Read16Bpp(IAMemory Memory, TextureInfo Texture) { int Width = Texture.Width; int Height = Texture.Height; @@ -273,7 +273,7 @@ namespace Ryujinx.HLE.Gpu return Output; } - private unsafe static byte[] Read8Bpt4x4(IAMemory Memory, Texture Texture) + private unsafe static byte[] Read8Bpt4x4(IAMemory Memory, TextureInfo Texture) { int Width = (Texture.Width + 3) / 4; int Height = (Texture.Height + 3) / 4; @@ -306,7 +306,7 @@ namespace Ryujinx.HLE.Gpu return Output; } - private unsafe static byte[] Read16Bpt4x4(IAMemory Memory, Texture Texture) + private unsafe static byte[] Read16Bpt4x4(IAMemory Memory, TextureInfo Texture) { int Width = (Texture.Width + 3) / 4; int Height = (Texture.Height + 3) / 4; diff --git a/Ryujinx.HLE/Gpu/TextureSwizzle.cs b/Ryujinx.HLE/Gpu/Texture/TextureSwizzle.cs similarity index 85% rename from Ryujinx.HLE/Gpu/TextureSwizzle.cs rename to Ryujinx.HLE/Gpu/Texture/TextureSwizzle.cs index 5e32f4c75..076df97ab 100644 --- a/Ryujinx.HLE/Gpu/TextureSwizzle.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureSwizzle.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Texture { enum TextureSwizzle { diff --git a/Ryujinx.HLE/Gpu/TextureWriter.cs b/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs similarity index 77% rename from Ryujinx.HLE/Gpu/TextureWriter.cs rename to Ryujinx.HLE/Gpu/Texture/TextureWriter.cs index ad92961c6..b64302a5a 100644 --- a/Ryujinx.HLE/Gpu/TextureWriter.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureWriter.cs @@ -2,16 +2,16 @@ using ChocolArm64.Memory; using Ryujinx.Graphics.Gal; using System; -namespace Ryujinx.HLE.Gpu +namespace Ryujinx.HLE.Gpu.Texture { static class TextureWriter { public static void Write( - IAMemory Memory, - Texture Texture, - byte[] Data, - int Width, - int Height) + IAMemory Memory, + TextureInfo Texture, + byte[] Data, + int Width, + int Height) { switch (Texture.Format) { @@ -22,11 +22,11 @@ namespace Ryujinx.HLE.Gpu } private unsafe static void Write4Bpp( - IAMemory Memory, - Texture Texture, - byte[] Data, - int Width, - int Height) + IAMemory Memory, + TextureInfo Texture, + byte[] Data, + int Width, + int Height) { ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 4); diff --git a/Ryujinx.HLE/Loaders/Npdm/ACI0.cs b/Ryujinx.HLE/Loaders/Npdm/ACI0.cs index 1f1b810ef..47b30a3c2 100644 --- a/Ryujinx.HLE/Loaders/Npdm/ACI0.cs +++ b/Ryujinx.HLE/Loaders/Npdm/ACI0.cs @@ -1,4 +1,3 @@ -using Ryujinx.HLE.OsHle.Utilities; using System; using System.IO; @@ -20,7 +19,7 @@ namespace Ryujinx.HLE.Loaders.Npdm public KernelAccessControl KernelAccessControl; public const long ACI0Magic = 'A' << 0 | 'C' << 8 | 'I' << 16 | '0' << 24; - + public ACI0(Stream ACI0Stream, int Offset) { ACI0Stream.Seek(Offset, SeekOrigin.Begin); diff --git a/Ryujinx.HLE/Loaders/Npdm/ACID.cs b/Ryujinx.HLE/Loaders/Npdm/ACID.cs index d0f0acdd5..09768a928 100644 --- a/Ryujinx.HLE/Loaders/Npdm/ACID.cs +++ b/Ryujinx.HLE/Loaders/Npdm/ACID.cs @@ -1,4 +1,3 @@ -using Ryujinx.HLE.OsHle.Utilities; using System; using System.IO; @@ -24,7 +23,7 @@ namespace Ryujinx.HLE.Loaders.Npdm public FSAccessControl FSAccessControl; public ServiceAccessControl ServiceAccessControl; public KernelAccessControl KernelAccessControl; - + public const long ACIDMagic = 'A' << 0 | 'C' << 8 | 'I' << 16 | 'D' << 24; public ACID(Stream ACIDStream, int Offset) diff --git a/Ryujinx.HLE/Loaders/Npdm/Npdm.cs b/Ryujinx.HLE/Loaders/Npdm/Npdm.cs index d255e668c..eaa662f03 100644 --- a/Ryujinx.HLE/Loaders/Npdm/Npdm.cs +++ b/Ryujinx.HLE/Loaders/Npdm/Npdm.cs @@ -1,6 +1,4 @@ using Ryujinx.HLE.OsHle.Utilities; -using System; -using System.Collections.Generic; using System.IO; using System.Text; @@ -29,7 +27,7 @@ namespace Ryujinx.HLE.Loaders.Npdm public ACI0 ACI0; public ACID ACID; - + public const long NpdmMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24; public Npdm(Stream NPDMStream) @@ -61,7 +59,7 @@ namespace Ryujinx.HLE.Loaders.Npdm // ProcessCategory (0: regular title, 1: kernel built-in). Should be 0 here. ProcessCategory = EndianSwap.Swap32(Reader.ReadInt32()); - // Main entrypoint stack size + // Main entrypoint stack size // (Should(?) be page-aligned. In non-nspwn scenarios, values of 0 can also rarely break in Horizon. // This might be something auto-adapting or a security feature of some sort ?) MainEntrypointStackSize = Reader.ReadInt32(); diff --git a/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs b/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs index fd33841a3..ddd7d7ed2 100644 --- a/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs +++ b/Ryujinx.HLE/Loaders/Npdm/ServiceAccessControl.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Text; @@ -25,7 +24,7 @@ namespace Ryujinx.HLE.Loaders.Npdm int Length = ((ControlByte & 0x07)) + 1; bool RegisterAllowed = ((ControlByte & 0x80) != 0); - + Services.Add((Encoding.ASCII.GetString(Reader.ReadBytes(Length), 0, Length), RegisterAllowed)); ByteReaded += Length + 1; diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs index c96c04c86..fcc478a41 100644 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs +++ b/Ryujinx.HLE/OsHle/Services/Nv/NvGpuAS/NvGpuASIoctl.cs @@ -1,5 +1,5 @@ using ChocolArm64.Memory; -using Ryujinx.HLE.Gpu; +using Ryujinx.HLE.Gpu.Memory; using Ryujinx.HLE.Logging; using Ryujinx.HLE.OsHle.Services.Nv.NvMap; using System; diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs index c461fa282..8f3d3cd7d 100644 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs +++ b/Ryujinx.HLE/OsHle/Services/Nv/NvHostChannel/NvHostChannelIoctl.cs @@ -1,5 +1,5 @@ using ChocolArm64.Memory; -using Ryujinx.HLE.Gpu; +using Ryujinx.HLE.Gpu.Memory; using Ryujinx.HLE.Logging; using Ryujinx.HLE.OsHle.Services.Nv.NvGpuAS; using System; diff --git a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapIoctl.cs b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapIoctl.cs index 43de4edb1..ec10a3758 100644 --- a/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapIoctl.cs +++ b/Ryujinx.HLE/OsHle/Services/Nv/NvMap/NvMapIoctl.cs @@ -1,5 +1,5 @@ using ChocolArm64.Memory; -using Ryujinx.HLE.Gpu; +using Ryujinx.HLE.Gpu.Memory; using Ryujinx.HLE.Logging; using Ryujinx.HLE.OsHle.Utilities; using System.Collections.Concurrent; diff --git a/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs index b45dac6b3..a3ed3ab51 100644 --- a/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs +++ b/Ryujinx.HLE/OsHle/Services/Vi/NvFlinger.cs @@ -1,5 +1,5 @@ using Ryujinx.Graphics.Gal; -using Ryujinx.HLE.Gpu; +using Ryujinx.HLE.Gpu.Texture; using Ryujinx.HLE.Logging; using Ryujinx.HLE.OsHle.Handles; using Ryujinx.HLE.OsHle.Services.Nv.NvMap; @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; + using static Ryujinx.HLE.OsHle.Services.Android.Parcel; namespace Ryujinx.HLE.OsHle.Services.Android @@ -339,7 +340,7 @@ namespace Ryujinx.HLE.OsHle.Services.Android Rotate = -MathF.PI * 0.5f; } - Renderer.SetFrameBufferTransform(ScaleX, ScaleY, Rotate, OffsX, OffsY); + Renderer.QueueAction(() => Renderer.FrameBuffer.SetTransform(ScaleX, ScaleY, Rotate, OffsX, OffsY)); //TODO: Support double buffering here aswell, it is broken for GPU //frame buffers because it seems to be completely out of sync. @@ -347,17 +348,17 @@ namespace Ryujinx.HLE.OsHle.Services.Android { //Frame buffer is rendered to by the GPU, we can just //bind the frame buffer texture, it's not necessary to read anything. - Renderer.SetFrameBuffer(FbAddr); + Renderer.QueueAction(() => Renderer.FrameBuffer.Set(FbAddr)); } else { //Frame buffer is not set on the GPU registers, in this case //assume that the app is manually writing to it. - Texture Texture = new Texture(FbAddr, FbWidth, FbHeight); + TextureInfo Texture = new TextureInfo(FbAddr, FbWidth, FbHeight); byte[] Data = TextureReader.Read(Context.Memory, Texture); - Renderer.SetFrameBuffer(Data, FbWidth, FbHeight); + Renderer.QueueAction(() => Renderer.FrameBuffer.Set(Data, FbWidth, FbHeight)); } Context.Ns.Gpu.Renderer.QueueAction(() => ReleaseBuffer(Slot)); diff --git a/Ryujinx.HLE/PerformanceStatistics.cs b/Ryujinx.HLE/PerformanceStatistics.cs index bbcdc6450..9bc3d6b47 100644 --- a/Ryujinx.HLE/PerformanceStatistics.cs +++ b/Ryujinx.HLE/PerformanceStatistics.cs @@ -1,84 +1,119 @@ using System.Diagnostics; using System.Timers; + namespace Ryujinx.HLE { public class PerformanceStatistics { - Stopwatch ExecutionTime = new Stopwatch(); - Timer ResetTimer = new Timer(1000); + private const double FrameRateWeight = 0.5; - long CurrentGameFrameEnded; - long CurrentSystemFrameEnded; - long CurrentSystemFrameStart; - long LastGameFrameEnded; - long LastSystemFrameEnded; + private const int FrameTypeSystem = 0; + private const int FrameTypeGame = 1; - double AccumulatedGameFrameTime; - double AccumulatedSystemFrameTime; - double CurrentGameFrameTime; - double CurrentSystemFrameTime; - double PreviousGameFrameTime; - double PreviousSystemFrameTime; - public double GameFrameRate { get; private set; } - public double SystemFrameRate { get; private set; } - public long SystemFramesRendered; - public long GameFramesRendered; - public long ElapsedMilliseconds => ExecutionTime.ElapsedMilliseconds; - public long ElapsedMicroseconds => (long) - (((double)ExecutionTime.ElapsedTicks / Stopwatch.Frequency) * 1000000); - public long ElapsedNanoseconds => (long) - (((double)ExecutionTime.ElapsedTicks / Stopwatch.Frequency) * 1000000000); + private double[] AverageFrameRate; + private double[] AccumulatedFrameTime; + private double[] PreviousFrameTime; + + private long[] FramesRendered; + + private object[] FrameLock; + + private double TicksToSeconds; + + private Stopwatch ExecutionTime; + + private Timer ResetTimer; public PerformanceStatistics() { + AverageFrameRate = new double[2]; + AccumulatedFrameTime = new double[2]; + PreviousFrameTime = new double[2]; + + FramesRendered = new long[2]; + + FrameLock = new object[] { new object(), new object() }; + + ExecutionTime = new Stopwatch(); + ExecutionTime.Start(); + + ResetTimer = new Timer(1000); + ResetTimer.Elapsed += ResetTimerElapsed; + ResetTimer.AutoReset = true; + ResetTimer.Start(); + + TicksToSeconds = 1.0 / Stopwatch.Frequency; } private void ResetTimerElapsed(object sender, ElapsedEventArgs e) { - ResetStatistics(); + CalculateAverageFrameRate(FrameTypeSystem); + CalculateAverageFrameRate(FrameTypeGame); } - public void StartSystemFrame() + private void CalculateAverageFrameRate(int FrameType) { - PreviousSystemFrameTime = CurrentSystemFrameTime; - LastSystemFrameEnded = CurrentSystemFrameEnded; - CurrentSystemFrameStart = ElapsedMicroseconds; + double FrameRate = 0; + + if (AccumulatedFrameTime[FrameType] > 0) + { + FrameRate = FramesRendered[FrameType] / AccumulatedFrameTime[FrameType]; + } + + lock (FrameLock[FrameType]) + { + AverageFrameRate[FrameType] = LinearInterpolate(AverageFrameRate[FrameType], FrameRate); + + FramesRendered[FrameType] = 0; + + AccumulatedFrameTime[FrameType] = 0; + } } - public void EndSystemFrame() + private double LinearInterpolate(double Old, double New) { - CurrentSystemFrameEnded = ElapsedMicroseconds; - CurrentSystemFrameTime = CurrentSystemFrameEnded - CurrentSystemFrameStart; - AccumulatedSystemFrameTime += CurrentSystemFrameTime; - SystemFramesRendered++; + return Old * (1.0 - FrameRateWeight) + New * FrameRateWeight; + } + + public void RecordSystemFrameTime() + { + RecordFrameTime(FrameTypeSystem); } public void RecordGameFrameTime() { - CurrentGameFrameEnded = ElapsedMicroseconds; - CurrentGameFrameTime = CurrentGameFrameEnded - LastGameFrameEnded; - PreviousGameFrameTime = CurrentGameFrameTime; - LastGameFrameEnded = CurrentGameFrameEnded; - AccumulatedGameFrameTime += CurrentGameFrameTime; - GameFramesRendered++; + RecordFrameTime(FrameTypeGame); } - public void ResetStatistics() + private void RecordFrameTime(int FrameType) { - GameFrameRate = 1000 / ((AccumulatedGameFrameTime / GameFramesRendered) / 1000); - GameFrameRate = double.IsNaN(GameFrameRate) ? 0 : GameFrameRate; - SystemFrameRate = 1000 / ((AccumulatedSystemFrameTime / SystemFramesRendered) / 1000); - SystemFrameRate = double.IsNaN(SystemFrameRate) ? 0 : SystemFrameRate; + double CurrentFrameTime = ExecutionTime.ElapsedTicks * TicksToSeconds; - GameFramesRendered = 0; - SystemFramesRendered = 0; - AccumulatedGameFrameTime = 0; - AccumulatedSystemFrameTime = 0; + double ElapsedFrameTime = CurrentFrameTime - PreviousFrameTime[FrameType]; + + PreviousFrameTime[FrameType] = CurrentFrameTime; + + lock (FrameLock[FrameType]) + { + AccumulatedFrameTime[FrameType] += ElapsedFrameTime; + + FramesRendered[FrameType]++; + } + } + + public double GetSystemFrameRate() + { + return AverageFrameRate[FrameTypeSystem]; + } + + public double GetGameFrameRate() + { + return AverageFrameRate[FrameTypeGame]; } } } diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index f75b24908..f7b263cd0 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -71,6 +71,11 @@ namespace Ryujinx.HLE Os.LoadProgram(FileName); } + public void ProcessFrame() + { + Gpu.Fifo.DispatchCalls(); + } + internal virtual void OnFinish(EventArgs e) { Finish?.Invoke(this, e); diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs index e2024b5bb..ab5eaa0f5 100644 --- a/Ryujinx/Ui/GLScreen.cs +++ b/Ryujinx/Ui/GLScreen.cs @@ -23,7 +23,7 @@ namespace Ryujinx private KeyboardState? Keyboard = null; private MouseState? Mouse = null; - + public GLScreen(Switch Ns, IGalRenderer Renderer) : base(1280, 720, new GraphicsMode(), "Ryujinx", 0, @@ -42,7 +42,7 @@ namespace Ryujinx { VSync = VSyncMode.On; - Renderer.SetWindowSize(Width, Height); + Renderer.FrameBuffer.SetWindowSize(Width, Height); } protected override void OnUpdateFrame(FrameEventArgs e) @@ -55,7 +55,7 @@ namespace Ryujinx int LeftJoystickDY = 0; int RightJoystickDX = 0; int RightJoystickDY = 0; - + if (Keyboard.HasValue) { KeyboardState Keyboard = this.Keyboard.Value; @@ -83,7 +83,7 @@ namespace Ryujinx if (Keyboard[(Key)Config.FakeJoyCon.Right.StickDown]) RightJoystickDY = -short.MaxValue; if (Keyboard[(Key)Config.FakeJoyCon.Right.StickLeft]) RightJoystickDX = -short.MaxValue; if (Keyboard[(Key)Config.FakeJoyCon.Right.StickRight]) RightJoystickDX = short.MaxValue; - + //RightButtons if (Keyboard[(Key)Config.FakeJoyCon.Right.StickButton]) CurrentButton |= HidControllerButtons.KEY_RSTICK; if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonA]) CurrentButton |= HidControllerButtons.KEY_A; @@ -179,28 +179,31 @@ namespace Ryujinx CurrentButton, LeftJoystick, RightJoystick); + + Ns.ProcessFrame(); + + Renderer.RunActions(); } protected override void OnRenderFrame(FrameEventArgs e) { - Ns.Statistics.StartSystemFrame(); + Renderer.FrameBuffer.Render(); - Title = $"Ryujinx Screen - (Vsync: {VSync} - FPS: {Ns.Statistics.SystemFrameRate:0} - Guest FPS: " + - $"{Ns.Statistics.GameFrameRate:0})"; + Ns.Statistics.RecordSystemFrameTime(); - Renderer.RunActions(); - Renderer.Render(); + double HostFps = Ns.Statistics.GetSystemFrameRate(); + double GameFps = Ns.Statistics.GetGameFrameRate(); + + Title = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0}"; SwapBuffers(); - Ns.Statistics.EndSystemFrame(); - Ns.Os.SignalVsync(); } protected override void OnResize(EventArgs e) { - Renderer.SetWindowSize(Width, Height); + Renderer.FrameBuffer.SetWindowSize(Width, Height); } protected override void OnKeyDown(KeyboardKeyEventArgs e) diff --git a/Ryujinx/Ui/Program.cs b/Ryujinx/Ui/Program.cs index 3bb16faf2..b14897695 100644 --- a/Ryujinx/Ui/Program.cs +++ b/Ryujinx/Ui/Program.cs @@ -14,7 +14,7 @@ namespace Ryujinx { Console.Title = "Ryujinx Console"; - IGalRenderer Renderer = new OpenGLRenderer(); + IGalRenderer Renderer = new OGLRenderer(); IAalOutput AudioOut = new OpenALAudioOut(); @@ -67,7 +67,7 @@ namespace Ryujinx Screen.Exit(); }; - Screen.Run(60.0); + Screen.Run(0.0, 60.0); } Environment.Exit(0);