forked from Mirror/Ryujinx
Small OpenGL Renderer refactoring (#177)
* Call OpenGL functions directly, remove the pfifo thread, some refactoring * Fix PerformanceStatistics calculating the wrong host fps, remove wait event on PFIFO as this wasn't exactly was causing the freezes (may replace with an exception later) * Organized the Gpu folder a bit more, renamed a few things, address PR feedback * Make PerformanceStatistics thread safe * Remove unused constant * Use unlimited update rate for better pref
This commit is contained in:
parent
69697957e6
commit
e7559f128f
58 changed files with 518 additions and 633 deletions
|
@ -1,6 +1,5 @@
|
||||||
using ChocolArm64.Translation;
|
using ChocolArm64.Translation;
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
|
||||||
|
|
||||||
namespace ChocolArm64.Instruction
|
namespace ChocolArm64.Instruction
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace Ryujinx.Graphics.Gal
|
|
||||||
{
|
|
||||||
public static class GalConsts
|
|
||||||
{
|
|
||||||
public const string FlipUniformName = "flip";
|
|
||||||
}
|
|
||||||
}
|
|
22
Ryujinx.Graphics/Gal/IGalBlend.cs
Normal file
22
Ryujinx.Graphics/Gal/IGalBlend.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
27
Ryujinx.Graphics/Gal/IGalFrameBuffer.cs
Normal file
27
Ryujinx.Graphics/Gal/IGalFrameBuffer.cs
Normal file
|
@ -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<byte[]> Callback);
|
||||||
|
}
|
||||||
|
}
|
23
Ryujinx.Graphics/Gal/IGalRasterizer.cs
Normal file
23
Ryujinx.Graphics/Gal/IGalRasterizer.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,90 +1,21 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal
|
namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public unsafe interface IGalRenderer
|
public interface IGalRenderer
|
||||||
{
|
{
|
||||||
void QueueAction(Action ActionMthd);
|
void QueueAction(Action ActionMthd);
|
||||||
|
|
||||||
void RunActions();
|
void RunActions();
|
||||||
|
|
||||||
void Render();
|
IGalBlend Blend { get; }
|
||||||
|
|
||||||
void SetWindowSize(int Width, int Height);
|
IGalFrameBuffer FrameBuffer { get; }
|
||||||
|
|
||||||
//Blend
|
IGalRasterizer Rasterizer { get; }
|
||||||
void SetBlendEnable(bool Enable);
|
|
||||||
|
|
||||||
void SetBlend(
|
IGalShader Shader { get; }
|
||||||
GalBlendEquation Equation,
|
|
||||||
GalBlendFactor FuncSrc,
|
|
||||||
GalBlendFactor FuncDst);
|
|
||||||
|
|
||||||
void SetBlendSeparate(
|
IGalTexture Texture { get; }
|
||||||
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<byte[]> 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<ShaderDeclInfo> 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
21
Ryujinx.Graphics/Gal/IGalShader.cs
Normal file
21
Ryujinx.Graphics/Gal/IGalShader.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public interface IGalShader
|
||||||
|
{
|
||||||
|
void Create(IGalMemory Memory, long Key, GalShaderType Type);
|
||||||
|
|
||||||
|
IEnumerable<ShaderDeclInfo> 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();
|
||||||
|
}
|
||||||
|
}
|
13
Ryujinx.Graphics/Gal/IGalTexture.cs
Normal file
13
Ryujinx.Graphics/Gal/IGalTexture.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ using OpenTK.Graphics.OpenGL;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
class OGLBlend
|
public class OGLBlend : IGalBlend
|
||||||
{
|
{
|
||||||
public void Enable()
|
public void Enable()
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
class OGLFrameBuffer
|
public class OGLFrameBuffer : IGalFrameBuffer
|
||||||
{
|
{
|
||||||
private struct Rect
|
private struct Rect
|
||||||
{
|
{
|
||||||
|
@ -16,9 +16,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public Rect(int X, int Y, int Width, int Height)
|
public Rect(int X, int Y, int Width, int Height)
|
||||||
{
|
{
|
||||||
this.X = X;
|
this.X = X;
|
||||||
this.Y = Y;
|
this.Y = Y;
|
||||||
this.Width = Width;
|
this.Width = Width;
|
||||||
this.Height = Height;
|
this.Height = Height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,14 +76,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Shader = new ShaderProgram();
|
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,
|
//TODO: We should either use the original frame buffer size,
|
||||||
//or just remove the Width/Height arguments.
|
//or just remove the Width/Height arguments.
|
||||||
Width = Window.Width;
|
Width = Window.Width;
|
||||||
Height = Window.Height;
|
Height = Window.Height;
|
||||||
|
|
||||||
if (Fbs.TryGetValue(Tag, out FrameBuffer Fb))
|
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
||||||
{
|
{
|
||||||
if (Fb.Width != Width ||
|
if (Fb.Width != Width ||
|
||||||
Fb.Height != Height)
|
Fb.Height != Height)
|
||||||
|
@ -127,12 +127,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
GL.Viewport(0, 0, Width, Height);
|
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);
|
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);
|
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;
|
CurrTexHandle = Fb.TexHandle;
|
||||||
}
|
}
|
||||||
|
@ -185,10 +185,17 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
CurrTexHandle = RawFbTexHandle;
|
CurrTexHandle = RawFbTexHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTransform(Matrix2 Transform, Vector2 Offs)
|
public void SetTransform(float SX, float SY, float Rotate, float TX, float TY)
|
||||||
{
|
{
|
||||||
EnsureInitialized();
|
EnsureInitialized();
|
||||||
|
|
||||||
|
Matrix2 Transform;
|
||||||
|
|
||||||
|
Transform = Matrix2.CreateScale(SX, SY);
|
||||||
|
Transform *= Matrix2.CreateRotation(Rotate);
|
||||||
|
|
||||||
|
Vector2 Offs = new Vector2(TX, TY);
|
||||||
|
|
||||||
int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram);
|
int CurrentProgram = GL.GetInteger(GetPName.CurrentProgram);
|
||||||
|
|
||||||
GL.UseProgram(Shader.Handle);
|
GL.UseProgram(Shader.Handle);
|
||||||
|
@ -270,9 +277,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetBufferData(long Tag, Action<byte[]> Callback)
|
public void GetBufferData(long Key, Action<byte[]> Callback)
|
||||||
{
|
{
|
||||||
if (Fbs.TryGetValue(Tag, out FrameBuffer Fb))
|
if (Fbs.TryGetValue(Key, out FrameBuffer Fb))
|
||||||
{
|
{
|
||||||
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, Fb.Handle);
|
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, Fb.Handle);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
class OGLRasterizer
|
public class OGLRasterizer : IGalRasterizer
|
||||||
{
|
{
|
||||||
private static Dictionary<GalVertexAttribSize, int> AttribElements =
|
private static Dictionary<GalVertexAttribSize, int> AttribElements =
|
||||||
new Dictionary<GalVertexAttribSize, int>()
|
new Dictionary<GalVertexAttribSize, int>()
|
||||||
|
@ -74,8 +74,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
ClearBufferMask Mask = 0;
|
ClearBufferMask Mask = 0;
|
||||||
|
|
||||||
//OpenGL doesn't support clearing just a single color channel,
|
//TODO: Use glColorMask to clear just the specified channels.
|
||||||
//so we can't just clear all channels...
|
|
||||||
if (Flags.HasFlag(GalClearBufferFlags.ColorRed) &&
|
if (Flags.HasFlag(GalClearBufferFlags.ColorRed) &&
|
||||||
Flags.HasFlag(GalClearBufferFlags.ColorGreen) &&
|
Flags.HasFlag(GalClearBufferFlags.ColorGreen) &&
|
||||||
Flags.HasFlag(GalClearBufferFlags.ColorBlue) &&
|
Flags.HasFlag(GalClearBufferFlags.ColorBlue) &&
|
||||||
|
@ -97,45 +96,43 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.Clear(Mask);
|
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();
|
int Handle = GL.GenBuffer();
|
||||||
|
|
||||||
VboCache.AddOrUpdate(Tag, Handle, (uint)Buffer.Length);
|
VboCache.AddOrUpdate(Key, Handle, (uint)Buffer.Length);
|
||||||
|
|
||||||
IntPtr Length = new IntPtr(Buffer.Length);
|
IntPtr Length = new IntPtr(Buffer.Length);
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
||||||
GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
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();
|
int Handle = GL.GenBuffer();
|
||||||
|
|
||||||
IboCache.AddOrUpdate(Tag, Handle, (uint)Buffer.Length);
|
IboCache.AddOrUpdate(Key, Handle, (uint)Buffer.Length);
|
||||||
|
|
||||||
IntPtr Length = new IntPtr(Buffer.Length);
|
IntPtr Length = new IntPtr(Buffer.Length);
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle);
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle);
|
||||||
GL.BufferData(BufferTarget.ElementArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -178,11 +175,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Stride, Offset);
|
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);
|
IndexBuffer.Type = OGLEnumConverter.GetDrawElementsType(Format);
|
||||||
|
|
||||||
|
@ -201,9 +196,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, PrimCount);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
50
Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs
Normal file
50
Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs
Normal file
|
@ -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<Action> ActionsQueue;
|
||||||
|
|
||||||
|
public OGLRenderer()
|
||||||
|
{
|
||||||
|
Blend = new OGLBlend();
|
||||||
|
|
||||||
|
FrameBuffer = new OGLFrameBuffer();
|
||||||
|
|
||||||
|
Rasterizer = new OGLRasterizer();
|
||||||
|
|
||||||
|
Shader = new OGLShader();
|
||||||
|
|
||||||
|
Texture = new OGLTexture();
|
||||||
|
|
||||||
|
ActionsQueue = new ConcurrentQueue<Action>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void QueueAction(Action ActionMthd)
|
||||||
|
{
|
||||||
|
ActionsQueue.Enqueue(ActionMthd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RunActions()
|
||||||
|
{
|
||||||
|
int Count = ActionsQueue.Count;
|
||||||
|
|
||||||
|
while (Count-- > 0 && ActionsQueue.TryDequeue(out Action RenderAction))
|
||||||
|
{
|
||||||
|
RenderAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ using System.Linq;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
class OGLShader
|
public class OGLShader : IGalShader
|
||||||
{
|
{
|
||||||
private class ShaderStage : IDisposable
|
private class ShaderStage : IDisposable
|
||||||
{
|
{
|
||||||
|
@ -84,9 +84,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Programs = new Dictionary<ShaderProgram, int>();
|
Programs = new Dictionary<ShaderProgram, int>();
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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);
|
return Decompiler.Decompile(Memory, Position + 0x50, Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Tag)
|
public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key)
|
||||||
{
|
{
|
||||||
if (Stages.TryGetValue(Tag, out ShaderStage Stage))
|
if (Stages.TryGetValue(Key, out ShaderStage Stage))
|
||||||
{
|
{
|
||||||
return Stage.TextureUsage;
|
return Stage.TextureUsage;
|
||||||
}
|
}
|
||||||
|
@ -117,11 +117,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
return Enumerable.Empty<ShaderDeclInfo>();
|
return Enumerable.Empty<ShaderDeclInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConstBuffer(long Tag, int Cbuf, byte[] Data)
|
public void SetConstBuffer(long Key, int Cbuf, byte[] Data)
|
||||||
{
|
{
|
||||||
BindProgram();
|
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))
|
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();
|
BindProgram();
|
||||||
|
|
||||||
|
@ -153,18 +153,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.Uniform1(Location, Value);
|
GL.Uniform1(Location, Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetUniform2F(string UniformName, float X, float Y)
|
public void SetFlip(float X, float Y)
|
||||||
{
|
{
|
||||||
BindProgram();
|
BindProgram();
|
||||||
|
|
||||||
int Location = GL.GetUniformLocation(CurrentProgramHandle, UniformName);
|
int Location = GL.GetUniformLocation(CurrentProgramHandle, GlslDecl.FlipUniformName);
|
||||||
|
|
||||||
GL.Uniform2(Location, X, Y);
|
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);
|
Bind(Stage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
class OGLTexture
|
public class OGLTexture : IGalTexture
|
||||||
{
|
{
|
||||||
private class TCE
|
private class TCE
|
||||||
{
|
{
|
||||||
|
@ -31,11 +31,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.DeleteTexture(CachedTexture.Handle);
|
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();
|
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);
|
GL.BindTexture(TextureTarget.Texture2D, Handle);
|
||||||
|
|
||||||
|
@ -146,11 +146,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
throw new ArgumentException(nameof(Format));
|
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;
|
Texture = CachedTexture.Texture;
|
||||||
|
|
||||||
|
@ -163,9 +163,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
return false;
|
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);
|
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 WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU);
|
||||||
int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV);
|
int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV);
|
||||||
|
|
|
@ -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<Action> ActionsQueue;
|
|
||||||
|
|
||||||
public OpenGLRenderer()
|
|
||||||
{
|
|
||||||
Blend = new OGLBlend();
|
|
||||||
|
|
||||||
FrameBuffer = new OGLFrameBuffer();
|
|
||||||
|
|
||||||
Rasterizer = new OGLRasterizer();
|
|
||||||
|
|
||||||
Shader = new OGLShader();
|
|
||||||
|
|
||||||
Texture = new OGLTexture();
|
|
||||||
|
|
||||||
ActionsQueue = new ConcurrentQueue<Action>();
|
|
||||||
}
|
|
||||||
|
|
||||||
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<byte[]> 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<ShaderDeclInfo> 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -26,6 +26,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
public const string FragmentOutputName = "FragColor";
|
public const string FragmentOutputName = "FragColor";
|
||||||
|
|
||||||
|
public const string FlipUniformName = "flip";
|
||||||
|
|
||||||
private string[] StagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" };
|
private string[] StagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" };
|
||||||
|
|
||||||
private string StagePrefix;
|
private string StagePrefix;
|
||||||
|
|
|
@ -140,7 +140,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
if (Decl.ShaderType == GalShaderType.Vertex)
|
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))
|
foreach (ShaderDeclInfo DeclInfo in Decl.Uniforms.Values.OrderBy(DeclKeySelector))
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
namespace Ryujinx.HLE.Gpu
|
using Ryujinx.HLE.Gpu.Memory;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
interface INvGpuEngine
|
interface INvGpuEngine
|
||||||
{
|
{
|
|
@ -1,10 +1,16 @@
|
||||||
|
using Ryujinx.HLE.Gpu.Exceptions;
|
||||||
|
using Ryujinx.HLE.Gpu.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
class MacroInterpreter
|
class MacroInterpreter
|
||||||
{
|
{
|
||||||
|
private const int MaxCallCountPerRun = 500;
|
||||||
|
|
||||||
|
private int CallCount;
|
||||||
|
|
||||||
private enum AssignmentOperation
|
private enum AssignmentOperation
|
||||||
{
|
{
|
||||||
IgnoreAndFetch = 0,
|
IgnoreAndFetch = 0,
|
||||||
|
@ -96,6 +102,8 @@ namespace Ryujinx.HLE.Gpu
|
||||||
MethIncr = 0;
|
MethIncr = 0;
|
||||||
|
|
||||||
Carry = false;
|
Carry = false;
|
||||||
|
|
||||||
|
CallCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool Step(NvGpuVmm Vmm, int[] Mme)
|
private bool Step(NvGpuVmm Vmm, int[] Mme)
|
||||||
|
@ -407,6 +415,15 @@ namespace Ryujinx.HLE.Gpu
|
||||||
|
|
||||||
private void Send(NvGpuVmm Vmm, int Value)
|
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);
|
NvGpuPBEntry PBEntry = new NvGpuPBEntry(MethAddr, 0, Value);
|
||||||
|
|
||||||
Engine.CallMethod(Vmm, PBEntry);
|
Engine.CallMethod(Vmm, PBEntry);
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
enum NvGpuEngine
|
enum NvGpuEngine
|
||||||
{
|
{
|
|
@ -1,7 +1,9 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
|
using Ryujinx.HLE.Gpu.Memory;
|
||||||
|
using Ryujinx.HLE.Gpu.Texture;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
class NvGpuEngine2d : INvGpuEngine
|
class NvGpuEngine2d : INvGpuEngine
|
||||||
{
|
{
|
||||||
|
@ -75,19 +77,19 @@ namespace Ryujinx.HLE.Gpu
|
||||||
|
|
||||||
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
|
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 SrcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress);
|
||||||
long DstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress);
|
long DstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress);
|
||||||
|
|
||||||
bool IsFbTexture = Gpu.Engine3d.IsFrameBufferPosition(Tag);
|
bool IsFbTexture = Gpu.Engine3d.IsFrameBufferPosition(Key);
|
||||||
|
|
||||||
if (IsFbTexture && DstLinear)
|
if (IsFbTexture && DstLinear)
|
||||||
{
|
{
|
||||||
DstSwizzle = TextureSwizzle.BlockLinear;
|
DstSwizzle = TextureSwizzle.BlockLinear;
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture DstTexture = new Texture(
|
TextureInfo DstTexture = new TextureInfo(
|
||||||
DstAddress,
|
DstAddress,
|
||||||
DstWidth,
|
DstWidth,
|
||||||
DstHeight,
|
DstHeight,
|
||||||
|
@ -103,7 +105,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
SrcWidth = 1280;
|
SrcWidth = 1280;
|
||||||
SrcHeight = 720;
|
SrcHeight = 720;
|
||||||
|
|
||||||
Gpu.Renderer.GetFrameBufferData(Tag, (byte[] Buffer) =>
|
Gpu.Renderer.FrameBuffer.GetBufferData(Key, (byte[] Buffer) =>
|
||||||
{
|
{
|
||||||
CopyTexture(
|
CopyTexture(
|
||||||
Vmm,
|
Vmm,
|
||||||
|
@ -129,11 +131,11 @@ namespace Ryujinx.HLE.Gpu
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CopyTexture(
|
private void CopyTexture(
|
||||||
NvGpuVmm Vmm,
|
NvGpuVmm Vmm,
|
||||||
Texture Texture,
|
TextureInfo Texture,
|
||||||
byte[] Buffer,
|
byte[] Buffer,
|
||||||
int Width,
|
int Width,
|
||||||
int Height)
|
int Height)
|
||||||
{
|
{
|
||||||
TextureWriter.Write(Vmm, Texture, Buffer, Width, Height);
|
TextureWriter.Write(Vmm, Texture, Buffer, Width, Height);
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
enum NvGpuEngine2dReg
|
enum NvGpuEngine2dReg
|
||||||
{
|
{
|
|
@ -1,8 +1,10 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
|
using Ryujinx.HLE.Gpu.Memory;
|
||||||
|
using Ryujinx.HLE.Gpu.Texture;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
class NvGpuEngine3d : INvGpuEngine
|
class NvGpuEngine3d : INvGpuEngine
|
||||||
{
|
{
|
||||||
|
@ -73,13 +75,13 @@ namespace Ryujinx.HLE.Gpu
|
||||||
{
|
{
|
||||||
SetFrameBuffer(Vmm, 0);
|
SetFrameBuffer(Vmm, 0);
|
||||||
|
|
||||||
long[] Tags = UploadShaders(Vmm);
|
long[] Keys = UploadShaders(Vmm);
|
||||||
|
|
||||||
Gpu.Renderer.BindProgram();
|
Gpu.Renderer.Shader.BindProgram();
|
||||||
|
|
||||||
SetAlphaBlending();
|
SetAlphaBlending();
|
||||||
|
|
||||||
UploadTextures(Vmm, Tags);
|
UploadTextures(Vmm, Keys);
|
||||||
UploadUniforms(Vmm);
|
UploadUniforms(Vmm);
|
||||||
UploadVertexArrays(Vmm);
|
UploadVertexArrays(Vmm);
|
||||||
}
|
}
|
||||||
|
@ -113,13 +115,13 @@ namespace Ryujinx.HLE.Gpu
|
||||||
|
|
||||||
//Note: Using the Width/Height results seems to give incorrect results.
|
//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.
|
//Maybe the size of all frame buffers is hardcoded to screen size? This seems unlikely.
|
||||||
Gpu.Renderer.CreateFrameBuffer(PA, 1280, 720);
|
Gpu.Renderer.FrameBuffer.Create(PA, 1280, 720);
|
||||||
Gpu.Renderer.BindFrameBuffer(PA);
|
Gpu.Renderer.FrameBuffer.Bind(PA);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long[] UploadShaders(NvGpuVmm Vmm)
|
private long[] UploadShaders(NvGpuVmm Vmm)
|
||||||
{
|
{
|
||||||
long[] Tags = new long[5];
|
long[] Keys = new long[5];
|
||||||
|
|
||||||
long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
||||||
|
|
||||||
|
@ -136,14 +138,14 @@ namespace Ryujinx.HLE.Gpu
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
long Tag = BasePosition + (uint)Offset;
|
long Key = BasePosition + (uint)Offset;
|
||||||
|
|
||||||
GalShaderType ShaderType = GetTypeFromProgram(Index);
|
GalShaderType ShaderType = GetTypeFromProgram(Index);
|
||||||
|
|
||||||
Tags[(int)ShaderType] = Tag;
|
Keys[(int)ShaderType] = Key;
|
||||||
|
|
||||||
Gpu.Renderer.CreateShader(Vmm, Tag, ShaderType);
|
Gpu.Renderer.Shader.Create(Vmm, Key, ShaderType);
|
||||||
Gpu.Renderer.BindShader(Tag);
|
Gpu.Renderer.Shader.Bind(Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawSX = ReadRegister(NvGpuEngine3dReg.ViewportScaleX);
|
int RawSX = ReadRegister(NvGpuEngine3dReg.ViewportScaleX);
|
||||||
|
@ -155,9 +157,9 @@ namespace Ryujinx.HLE.Gpu
|
||||||
float SignX = MathF.Sign(SX);
|
float SignX = MathF.Sign(SX);
|
||||||
float SignY = MathF.Sign(SY);
|
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)
|
private static GalShaderType GetTypeFromProgram(int Program)
|
||||||
|
@ -180,7 +182,14 @@ namespace Ryujinx.HLE.Gpu
|
||||||
//TODO: Support independent blend properly.
|
//TODO: Support independent blend properly.
|
||||||
bool Enable = (ReadRegister(NvGpuEngine3dReg.IBlendNEnable) & 1) != 0;
|
bool Enable = (ReadRegister(NvGpuEngine3dReg.IBlendNEnable) & 1) != 0;
|
||||||
|
|
||||||
Gpu.Renderer.SetBlendEnable(Enable);
|
if (Enable)
|
||||||
|
{
|
||||||
|
Gpu.Renderer.Blend.Enable();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Gpu.Renderer.Blend.Disable();
|
||||||
|
}
|
||||||
|
|
||||||
if (!Enable)
|
if (!Enable)
|
||||||
{
|
{
|
||||||
|
@ -203,7 +212,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
GalBlendFactor FuncSrcAlpha = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncSrcAlpha);
|
GalBlendFactor FuncSrcAlpha = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncSrcAlpha);
|
||||||
GalBlendFactor FuncDstAlpha = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncDstAlpha);
|
GalBlendFactor FuncDstAlpha = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncDstAlpha);
|
||||||
|
|
||||||
Gpu.Renderer.SetBlendSeparate(
|
Gpu.Renderer.Blend.SetSeparate(
|
||||||
EquationRgb,
|
EquationRgb,
|
||||||
EquationAlpha,
|
EquationAlpha,
|
||||||
FuncSrcRgb,
|
FuncSrcRgb,
|
||||||
|
@ -213,11 +222,11 @@ namespace Ryujinx.HLE.Gpu
|
||||||
}
|
}
|
||||||
else
|
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);
|
long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
||||||
|
|
||||||
|
@ -227,15 +236,15 @@ namespace Ryujinx.HLE.Gpu
|
||||||
//reserved for drawing the frame buffer.
|
//reserved for drawing the frame buffer.
|
||||||
int TexIndex = 1;
|
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;
|
long Position = ConstBuffers[Index][TextureCbIndex].Position;
|
||||||
|
|
||||||
UploadTexture(Vmm, Position, TexIndex, DeclInfo.Index);
|
UploadTexture(Vmm, Position, TexIndex, DeclInfo.Index);
|
||||||
|
|
||||||
Gpu.Renderer.SetUniform1(DeclInfo.Name, TexIndex);
|
Gpu.Renderer.Shader.EnsureTextureBinding(DeclInfo.Name, TexIndex);
|
||||||
|
|
||||||
TexIndex++;
|
TexIndex++;
|
||||||
}
|
}
|
||||||
|
@ -270,7 +279,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
|
|
||||||
long TextureAddress = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff;
|
long TextureAddress = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff;
|
||||||
|
|
||||||
long Tag = TextureAddress;
|
long Key = TextureAddress;
|
||||||
|
|
||||||
TextureAddress = Vmm.GetPhysicalAddress(TextureAddress);
|
TextureAddress = Vmm.GetPhysicalAddress(TextureAddress);
|
||||||
|
|
||||||
|
@ -280,7 +289,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
//we shouldn't read anything from memory and bind
|
//we shouldn't read anything from memory and bind
|
||||||
//the frame buffer texture instead, since we're not
|
//the frame buffer texture instead, since we're not
|
||||||
//really writing anything to memory.
|
//really writing anything to memory.
|
||||||
Gpu.Renderer.BindFrameBufferTexture(TextureAddress, TexIndex, Sampler);
|
Gpu.Renderer.FrameBuffer.BindTexture(TextureAddress, TexIndex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -288,22 +297,29 @@ namespace Ryujinx.HLE.Gpu
|
||||||
|
|
||||||
long Size = (uint)TextureHelper.GetTextureSize(NewTexture);
|
long Size = (uint)TextureHelper.GetTextureSize(NewTexture);
|
||||||
|
|
||||||
if (Gpu.Renderer.TryGetCachedTexture(Tag, Size, out GalTexture Texture))
|
bool HasCachedTexture = false;
|
||||||
{
|
|
||||||
if (NewTexture.Equals(Texture) && !Vmm.IsRegionModified(Tag, Size, NvGpuBufferType.Texture))
|
|
||||||
{
|
|
||||||
Gpu.Renderer.BindTexture(Tag, TexIndex);
|
|
||||||
|
|
||||||
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)
|
private void UploadUniforms(NvGpuVmm Vmm)
|
||||||
|
@ -331,7 +347,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
{
|
{
|
||||||
byte[] Data = Vmm.ReadBytes(Cb.Position, (uint)Cb.Size);
|
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);
|
long IndexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress);
|
||||||
|
|
||||||
int IndexSize = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat);
|
int IndexEntryFmt = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat);
|
||||||
int IndexFirst = ReadRegister(NvGpuEngine3dReg.IndexBatchFirst);
|
int IndexFirst = ReadRegister(NvGpuEngine3dReg.IndexBatchFirst);
|
||||||
int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount);
|
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();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IndexCount != 0)
|
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))
|
if (!IboCached || Vmm.IsRegionModified(IndexPosition, (uint)IbSize, NvGpuBufferType.Index))
|
||||||
{
|
{
|
||||||
byte[] Data = Vmm.ReadBytes(IndexPosition, (uint)IbSize);
|
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<GalVertexAttrib>[] Attribs = new List<GalVertexAttrib>[32];
|
List<GalVertexAttrib>[] Attribs = new List<GalVertexAttrib>[32];
|
||||||
|
@ -429,27 +445,27 @@ namespace Ryujinx.HLE.Gpu
|
||||||
VbSize = VertexCount * Stride;
|
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))
|
if (!VboCached || Vmm.IsRegionModified(VertexPosition, VbSize, NvGpuBufferType.Vertex))
|
||||||
{
|
{
|
||||||
byte[] Data = Vmm.ReadBytes(VertexPosition, VbSize);
|
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);
|
GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff);
|
||||||
|
|
||||||
if (IndexCount != 0)
|
if (IndexCount != 0)
|
||||||
{
|
{
|
||||||
Gpu.Renderer.DrawElements(IndexPosition, IndexFirst, PrimType);
|
Gpu.Renderer.Rasterizer.DrawElements(IndexPosition, IndexFirst, PrimType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Gpu.Renderer.DrawArrays(VertexFirst, VertexCount, PrimType);
|
Gpu.Renderer.Rasterizer.DrawArrays(VertexFirst, VertexCount, PrimType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
enum NvGpuEngine3dReg
|
enum NvGpuEngine3dReg
|
||||||
{
|
{
|
|
@ -1,6 +1,8 @@
|
||||||
|
using Ryujinx.HLE.Gpu.Memory;
|
||||||
|
using Ryujinx.HLE.Gpu.Texture;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
class NvGpuEngineDma : INvGpuEngine
|
class NvGpuEngineDma : INvGpuEngine
|
||||||
{
|
{
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
enum NvGpuEngineDmaReg
|
enum NvGpuEngineDmaReg
|
||||||
{
|
{
|
|
@ -1,6 +1,7 @@
|
||||||
|
using Ryujinx.HLE.Gpu.Memory;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
class NvGpuFifo
|
class NvGpuFifo
|
||||||
{
|
{
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Engines
|
||||||
{
|
{
|
||||||
enum NvGpuFifoMeth
|
enum NvGpuFifoMeth
|
||||||
{
|
{
|
|
@ -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);
|
delegate void NvGpuMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry);
|
||||||
}
|
}
|
11
Ryujinx.HLE/Gpu/Exceptions/GpuException.cs
Normal file
11
Ryujinx.HLE/Gpu/Exceptions/GpuException.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.Gpu.Exceptions
|
||||||
|
{
|
||||||
|
class GpuException : Exception
|
||||||
|
{
|
||||||
|
public GpuException() : base() { }
|
||||||
|
|
||||||
|
public GpuException(string ExMsg) : base(ExMsg) { }
|
||||||
|
}
|
||||||
|
}
|
12
Ryujinx.HLE/Gpu/Exceptions/GpuExceptionHelper.cs
Normal file
12
Ryujinx.HLE/Gpu/Exceptions/GpuExceptionHelper.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Memory
|
||||||
{
|
{
|
||||||
enum NvGpuBufferType
|
enum NvGpuBufferType
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Memory
|
||||||
{
|
{
|
||||||
struct NvGpuPBEntry
|
struct NvGpuPBEntry
|
||||||
{
|
{
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Memory
|
||||||
{
|
{
|
||||||
static class NvGpuPushBuffer
|
static class NvGpuPushBuffer
|
||||||
{
|
{
|
|
@ -2,7 +2,7 @@ using ChocolArm64.Memory;
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Memory
|
||||||
{
|
{
|
||||||
class NvGpuVmm : IAMemory, IGalMemory
|
class NvGpuVmm : IAMemory, IGalMemory
|
||||||
{
|
{
|
|
@ -2,7 +2,7 @@ using ChocolArm64.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Memory
|
||||||
{
|
{
|
||||||
class NvGpuVmmCache
|
class NvGpuVmmCache
|
||||||
{
|
{
|
|
@ -1,5 +1,5 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using System.Threading;
|
using Ryujinx.HLE.Gpu.Engines;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu
|
||||||
{
|
{
|
||||||
|
@ -13,10 +13,6 @@ namespace Ryujinx.HLE.Gpu
|
||||||
public NvGpuEngine3d Engine3d { get; private set; }
|
public NvGpuEngine3d Engine3d { get; private set; }
|
||||||
public NvGpuEngineDma EngineDma { get; private set; }
|
public NvGpuEngineDma EngineDma { get; private set; }
|
||||||
|
|
||||||
private Thread FifoProcessing;
|
|
||||||
|
|
||||||
private bool KeepRunning;
|
|
||||||
|
|
||||||
public NvGpu(IGalRenderer Renderer)
|
public NvGpu(IGalRenderer Renderer)
|
||||||
{
|
{
|
||||||
this.Renderer = Renderer;
|
this.Renderer = Renderer;
|
||||||
|
@ -26,22 +22,6 @@ namespace Ryujinx.HLE.Gpu
|
||||||
Engine2d = new NvGpuEngine2d(this);
|
Engine2d = new NvGpuEngine2d(this);
|
||||||
Engine3d = new NvGpuEngine3d(this);
|
Engine3d = new NvGpuEngine3d(this);
|
||||||
EngineDma = new NvGpuEngineDma(this);
|
EngineDma = new NvGpuEngineDma(this);
|
||||||
|
|
||||||
KeepRunning = true;
|
|
||||||
|
|
||||||
FifoProcessing = new Thread(ProcessFifo);
|
|
||||||
|
|
||||||
FifoProcessing.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProcessFifo()
|
|
||||||
{
|
|
||||||
while (KeepRunning)
|
|
||||||
{
|
|
||||||
Fifo.DispatchCalls();
|
|
||||||
|
|
||||||
Thread.Yield();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Texture
|
||||||
{
|
{
|
||||||
class BlockLinearSwizzle : ISwizzle
|
class BlockLinearSwizzle : ISwizzle
|
||||||
{
|
{
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Texture
|
||||||
{
|
{
|
||||||
interface ISwizzle
|
interface ISwizzle
|
||||||
{
|
{
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Texture
|
||||||
{
|
{
|
||||||
class LinearSwizzle : ISwizzle
|
class LinearSwizzle : ISwizzle
|
||||||
{
|
{
|
|
@ -1,7 +1,8 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
|
using Ryujinx.HLE.Gpu.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Texture
|
||||||
{
|
{
|
||||||
static class TextureFactory
|
static class TextureFactory
|
||||||
{
|
{
|
||||||
|
@ -61,7 +62,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
int Width = (Tic[4] & 0xffff) + 1;
|
int Width = (Tic[4] & 0xffff) + 1;
|
||||||
int Height = (Tic[5] & 0xffff) + 1;
|
int Height = (Tic[5] & 0xffff) + 1;
|
||||||
|
|
||||||
Texture Texture = new Texture(
|
TextureInfo Texture = new TextureInfo(
|
||||||
TextureAddress,
|
TextureAddress,
|
||||||
Width,
|
Width,
|
||||||
Height,
|
Height,
|
|
@ -1,12 +1,13 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
|
using Ryujinx.HLE.Gpu.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Texture
|
||||||
{
|
{
|
||||||
static class TextureHelper
|
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)
|
switch (Texture.Swizzle)
|
||||||
{
|
{
|
|
@ -1,8 +1,8 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Texture
|
||||||
{
|
{
|
||||||
struct Texture
|
struct TextureInfo
|
||||||
{
|
{
|
||||||
public long Position { get; private set; }
|
public long Position { get; private set; }
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
|
|
||||||
public GalTextureFormat Format { get; private set; }
|
public GalTextureFormat Format { get; private set; }
|
||||||
|
|
||||||
public Texture(
|
public TextureInfo(
|
||||||
long Position,
|
long Position,
|
||||||
int Width,
|
int Width,
|
||||||
int Height)
|
int Height)
|
||||||
|
@ -34,7 +34,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
Format = GalTextureFormat.A8B8G8R8;
|
Format = GalTextureFormat.A8B8G8R8;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Texture(
|
public TextureInfo(
|
||||||
long Position,
|
long Position,
|
||||||
int Width,
|
int Width,
|
||||||
int Height,
|
int Height,
|
|
@ -2,11 +2,11 @@ using ChocolArm64.Memory;
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Texture
|
||||||
{
|
{
|
||||||
static class TextureReader
|
static class TextureReader
|
||||||
{
|
{
|
||||||
public static byte[] Read(IAMemory Memory, Texture Texture)
|
public static byte[] Read(IAMemory Memory, TextureInfo Texture)
|
||||||
{
|
{
|
||||||
switch (Texture.Format)
|
switch (Texture.Format)
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
throw new NotImplementedException(Texture.Format.ToString());
|
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 Width = Texture.Width;
|
||||||
int Height = Texture.Height;
|
int Height = Texture.Height;
|
||||||
|
@ -64,7 +64,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
return Output;
|
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 Width = Texture.Width;
|
||||||
int Height = Texture.Height;
|
int Height = Texture.Height;
|
||||||
|
@ -102,7 +102,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
return Output;
|
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 Width = Texture.Width;
|
||||||
int Height = Texture.Height;
|
int Height = Texture.Height;
|
||||||
|
@ -139,7 +139,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
return Output;
|
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 Width = Texture.Width;
|
||||||
int Height = Texture.Height;
|
int Height = Texture.Height;
|
||||||
|
@ -172,7 +172,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
return Output;
|
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 Width = Texture.Width;
|
||||||
int Height = Texture.Height;
|
int Height = Texture.Height;
|
||||||
|
@ -205,7 +205,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
return Output;
|
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 Width = Texture.Width;
|
||||||
int Height = Texture.Height;
|
int Height = Texture.Height;
|
||||||
|
@ -238,7 +238,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
return Output;
|
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 Width = Texture.Width;
|
||||||
int Height = Texture.Height;
|
int Height = Texture.Height;
|
||||||
|
@ -273,7 +273,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
return Output;
|
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 Width = (Texture.Width + 3) / 4;
|
||||||
int Height = (Texture.Height + 3) / 4;
|
int Height = (Texture.Height + 3) / 4;
|
||||||
|
@ -306,7 +306,7 @@ namespace Ryujinx.HLE.Gpu
|
||||||
return Output;
|
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 Width = (Texture.Width + 3) / 4;
|
||||||
int Height = (Texture.Height + 3) / 4;
|
int Height = (Texture.Height + 3) / 4;
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Texture
|
||||||
{
|
{
|
||||||
enum TextureSwizzle
|
enum TextureSwizzle
|
||||||
{
|
{
|
|
@ -2,16 +2,16 @@ using ChocolArm64.Memory;
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu.Texture
|
||||||
{
|
{
|
||||||
static class TextureWriter
|
static class TextureWriter
|
||||||
{
|
{
|
||||||
public static void Write(
|
public static void Write(
|
||||||
IAMemory Memory,
|
IAMemory Memory,
|
||||||
Texture Texture,
|
TextureInfo Texture,
|
||||||
byte[] Data,
|
byte[] Data,
|
||||||
int Width,
|
int Width,
|
||||||
int Height)
|
int Height)
|
||||||
{
|
{
|
||||||
switch (Texture.Format)
|
switch (Texture.Format)
|
||||||
{
|
{
|
||||||
|
@ -22,11 +22,11 @@ namespace Ryujinx.HLE.Gpu
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe static void Write4Bpp(
|
private unsafe static void Write4Bpp(
|
||||||
IAMemory Memory,
|
IAMemory Memory,
|
||||||
Texture Texture,
|
TextureInfo Texture,
|
||||||
byte[] Data,
|
byte[] Data,
|
||||||
int Width,
|
int Width,
|
||||||
int Height)
|
int Height)
|
||||||
{
|
{
|
||||||
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 4);
|
ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 4);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using Ryujinx.HLE.OsHle.Utilities;
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
@ -20,7 +19,7 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
||||||
public KernelAccessControl KernelAccessControl;
|
public KernelAccessControl KernelAccessControl;
|
||||||
|
|
||||||
public const long ACI0Magic = 'A' << 0 | 'C' << 8 | 'I' << 16 | '0' << 24;
|
public const long ACI0Magic = 'A' << 0 | 'C' << 8 | 'I' << 16 | '0' << 24;
|
||||||
|
|
||||||
public ACI0(Stream ACI0Stream, int Offset)
|
public ACI0(Stream ACI0Stream, int Offset)
|
||||||
{
|
{
|
||||||
ACI0Stream.Seek(Offset, SeekOrigin.Begin);
|
ACI0Stream.Seek(Offset, SeekOrigin.Begin);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using Ryujinx.HLE.OsHle.Utilities;
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
@ -24,7 +23,7 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
||||||
public FSAccessControl FSAccessControl;
|
public FSAccessControl FSAccessControl;
|
||||||
public ServiceAccessControl ServiceAccessControl;
|
public ServiceAccessControl ServiceAccessControl;
|
||||||
public KernelAccessControl KernelAccessControl;
|
public KernelAccessControl KernelAccessControl;
|
||||||
|
|
||||||
public const long ACIDMagic = 'A' << 0 | 'C' << 8 | 'I' << 16 | 'D' << 24;
|
public const long ACIDMagic = 'A' << 0 | 'C' << 8 | 'I' << 16 | 'D' << 24;
|
||||||
|
|
||||||
public ACID(Stream ACIDStream, int Offset)
|
public ACID(Stream ACIDStream, int Offset)
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
using Ryujinx.HLE.OsHle.Utilities;
|
using Ryujinx.HLE.OsHle.Utilities;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
@ -29,7 +27,7 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
||||||
|
|
||||||
public ACI0 ACI0;
|
public ACI0 ACI0;
|
||||||
public ACID ACID;
|
public ACID ACID;
|
||||||
|
|
||||||
public const long NpdmMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24;
|
public const long NpdmMagic = 'M' << 0 | 'E' << 8 | 'T' << 16 | 'A' << 24;
|
||||||
|
|
||||||
public Npdm(Stream NPDMStream)
|
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 (0: regular title, 1: kernel built-in). Should be 0 here.
|
||||||
ProcessCategory = EndianSwap.Swap32(Reader.ReadInt32());
|
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.
|
// (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 ?)
|
// This might be something auto-adapting or a security feature of some sort ?)
|
||||||
MainEntrypointStackSize = Reader.ReadInt32();
|
MainEntrypointStackSize = Reader.ReadInt32();
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
@ -25,7 +24,7 @@ namespace Ryujinx.HLE.Loaders.Npdm
|
||||||
|
|
||||||
int Length = ((ControlByte & 0x07)) + 1;
|
int Length = ((ControlByte & 0x07)) + 1;
|
||||||
bool RegisterAllowed = ((ControlByte & 0x80) != 0);
|
bool RegisterAllowed = ((ControlByte & 0x80) != 0);
|
||||||
|
|
||||||
Services.Add((Encoding.ASCII.GetString(Reader.ReadBytes(Length), 0, Length), RegisterAllowed));
|
Services.Add((Encoding.ASCII.GetString(Reader.ReadBytes(Length), 0, Length), RegisterAllowed));
|
||||||
|
|
||||||
ByteReaded += Length + 1;
|
ByteReaded += Length + 1;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.HLE.Gpu;
|
using Ryujinx.HLE.Gpu.Memory;
|
||||||
using Ryujinx.HLE.Logging;
|
using Ryujinx.HLE.Logging;
|
||||||
using Ryujinx.HLE.OsHle.Services.Nv.NvMap;
|
using Ryujinx.HLE.OsHle.Services.Nv.NvMap;
|
||||||
using System;
|
using System;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.HLE.Gpu;
|
using Ryujinx.HLE.Gpu.Memory;
|
||||||
using Ryujinx.HLE.Logging;
|
using Ryujinx.HLE.Logging;
|
||||||
using Ryujinx.HLE.OsHle.Services.Nv.NvGpuAS;
|
using Ryujinx.HLE.OsHle.Services.Nv.NvGpuAS;
|
||||||
using System;
|
using System;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.HLE.Gpu;
|
using Ryujinx.HLE.Gpu.Memory;
|
||||||
using Ryujinx.HLE.Logging;
|
using Ryujinx.HLE.Logging;
|
||||||
using Ryujinx.HLE.OsHle.Utilities;
|
using Ryujinx.HLE.OsHle.Utilities;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using Ryujinx.HLE.Gpu;
|
using Ryujinx.HLE.Gpu.Texture;
|
||||||
using Ryujinx.HLE.Logging;
|
using Ryujinx.HLE.Logging;
|
||||||
using Ryujinx.HLE.OsHle.Handles;
|
using Ryujinx.HLE.OsHle.Handles;
|
||||||
using Ryujinx.HLE.OsHle.Services.Nv.NvMap;
|
using Ryujinx.HLE.OsHle.Services.Nv.NvMap;
|
||||||
|
@ -8,6 +8,7 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
using static Ryujinx.HLE.OsHle.Services.Android.Parcel;
|
using static Ryujinx.HLE.OsHle.Services.Android.Parcel;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.OsHle.Services.Android
|
namespace Ryujinx.HLE.OsHle.Services.Android
|
||||||
|
@ -339,7 +340,7 @@ namespace Ryujinx.HLE.OsHle.Services.Android
|
||||||
Rotate = -MathF.PI * 0.5f;
|
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
|
//TODO: Support double buffering here aswell, it is broken for GPU
|
||||||
//frame buffers because it seems to be completely out of sync.
|
//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
|
//Frame buffer is rendered to by the GPU, we can just
|
||||||
//bind the frame buffer texture, it's not necessary to read anything.
|
//bind the frame buffer texture, it's not necessary to read anything.
|
||||||
Renderer.SetFrameBuffer(FbAddr);
|
Renderer.QueueAction(() => Renderer.FrameBuffer.Set(FbAddr));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Frame buffer is not set on the GPU registers, in this case
|
//Frame buffer is not set on the GPU registers, in this case
|
||||||
//assume that the app is manually writing to it.
|
//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);
|
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));
|
Context.Ns.Gpu.Renderer.QueueAction(() => ReleaseBuffer(Slot));
|
||||||
|
|
|
@ -1,84 +1,119 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE
|
namespace Ryujinx.HLE
|
||||||
{
|
{
|
||||||
public class PerformanceStatistics
|
public class PerformanceStatistics
|
||||||
{
|
{
|
||||||
Stopwatch ExecutionTime = new Stopwatch();
|
private const double FrameRateWeight = 0.5;
|
||||||
Timer ResetTimer = new Timer(1000);
|
|
||||||
|
|
||||||
long CurrentGameFrameEnded;
|
private const int FrameTypeSystem = 0;
|
||||||
long CurrentSystemFrameEnded;
|
private const int FrameTypeGame = 1;
|
||||||
long CurrentSystemFrameStart;
|
|
||||||
long LastGameFrameEnded;
|
|
||||||
long LastSystemFrameEnded;
|
|
||||||
|
|
||||||
double AccumulatedGameFrameTime;
|
private double[] AverageFrameRate;
|
||||||
double AccumulatedSystemFrameTime;
|
private double[] AccumulatedFrameTime;
|
||||||
double CurrentGameFrameTime;
|
private double[] PreviousFrameTime;
|
||||||
double CurrentSystemFrameTime;
|
|
||||||
double PreviousGameFrameTime;
|
private long[] FramesRendered;
|
||||||
double PreviousSystemFrameTime;
|
|
||||||
public double GameFrameRate { get; private set; }
|
private object[] FrameLock;
|
||||||
public double SystemFrameRate { get; private set; }
|
|
||||||
public long SystemFramesRendered;
|
private double TicksToSeconds;
|
||||||
public long GameFramesRendered;
|
|
||||||
public long ElapsedMilliseconds => ExecutionTime.ElapsedMilliseconds;
|
private Stopwatch ExecutionTime;
|
||||||
public long ElapsedMicroseconds => (long)
|
|
||||||
(((double)ExecutionTime.ElapsedTicks / Stopwatch.Frequency) * 1000000);
|
private Timer ResetTimer;
|
||||||
public long ElapsedNanoseconds => (long)
|
|
||||||
(((double)ExecutionTime.ElapsedTicks / Stopwatch.Frequency) * 1000000000);
|
|
||||||
|
|
||||||
public PerformanceStatistics()
|
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();
|
ExecutionTime.Start();
|
||||||
|
|
||||||
|
ResetTimer = new Timer(1000);
|
||||||
|
|
||||||
ResetTimer.Elapsed += ResetTimerElapsed;
|
ResetTimer.Elapsed += ResetTimerElapsed;
|
||||||
|
|
||||||
ResetTimer.AutoReset = true;
|
ResetTimer.AutoReset = true;
|
||||||
|
|
||||||
ResetTimer.Start();
|
ResetTimer.Start();
|
||||||
|
|
||||||
|
TicksToSeconds = 1.0 / Stopwatch.Frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResetTimerElapsed(object sender, ElapsedEventArgs e)
|
private void ResetTimerElapsed(object sender, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
ResetStatistics();
|
CalculateAverageFrameRate(FrameTypeSystem);
|
||||||
|
CalculateAverageFrameRate(FrameTypeGame);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartSystemFrame()
|
private void CalculateAverageFrameRate(int FrameType)
|
||||||
{
|
{
|
||||||
PreviousSystemFrameTime = CurrentSystemFrameTime;
|
double FrameRate = 0;
|
||||||
LastSystemFrameEnded = CurrentSystemFrameEnded;
|
|
||||||
CurrentSystemFrameStart = ElapsedMicroseconds;
|
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;
|
return Old * (1.0 - FrameRateWeight) + New * FrameRateWeight;
|
||||||
CurrentSystemFrameTime = CurrentSystemFrameEnded - CurrentSystemFrameStart;
|
}
|
||||||
AccumulatedSystemFrameTime += CurrentSystemFrameTime;
|
|
||||||
SystemFramesRendered++;
|
public void RecordSystemFrameTime()
|
||||||
|
{
|
||||||
|
RecordFrameTime(FrameTypeSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RecordGameFrameTime()
|
public void RecordGameFrameTime()
|
||||||
{
|
{
|
||||||
CurrentGameFrameEnded = ElapsedMicroseconds;
|
RecordFrameTime(FrameTypeGame);
|
||||||
CurrentGameFrameTime = CurrentGameFrameEnded - LastGameFrameEnded;
|
|
||||||
PreviousGameFrameTime = CurrentGameFrameTime;
|
|
||||||
LastGameFrameEnded = CurrentGameFrameEnded;
|
|
||||||
AccumulatedGameFrameTime += CurrentGameFrameTime;
|
|
||||||
GameFramesRendered++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResetStatistics()
|
private void RecordFrameTime(int FrameType)
|
||||||
{
|
{
|
||||||
GameFrameRate = 1000 / ((AccumulatedGameFrameTime / GameFramesRendered) / 1000);
|
double CurrentFrameTime = ExecutionTime.ElapsedTicks * TicksToSeconds;
|
||||||
GameFrameRate = double.IsNaN(GameFrameRate) ? 0 : GameFrameRate;
|
|
||||||
SystemFrameRate = 1000 / ((AccumulatedSystemFrameTime / SystemFramesRendered) / 1000);
|
|
||||||
SystemFrameRate = double.IsNaN(SystemFrameRate) ? 0 : SystemFrameRate;
|
|
||||||
|
|
||||||
GameFramesRendered = 0;
|
double ElapsedFrameTime = CurrentFrameTime - PreviousFrameTime[FrameType];
|
||||||
SystemFramesRendered = 0;
|
|
||||||
AccumulatedGameFrameTime = 0;
|
PreviousFrameTime[FrameType] = CurrentFrameTime;
|
||||||
AccumulatedSystemFrameTime = 0;
|
|
||||||
|
lock (FrameLock[FrameType])
|
||||||
|
{
|
||||||
|
AccumulatedFrameTime[FrameType] += ElapsedFrameTime;
|
||||||
|
|
||||||
|
FramesRendered[FrameType]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double GetSystemFrameRate()
|
||||||
|
{
|
||||||
|
return AverageFrameRate[FrameTypeSystem];
|
||||||
|
}
|
||||||
|
|
||||||
|
public double GetGameFrameRate()
|
||||||
|
{
|
||||||
|
return AverageFrameRate[FrameTypeGame];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,11 @@ namespace Ryujinx.HLE
|
||||||
Os.LoadProgram(FileName);
|
Os.LoadProgram(FileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ProcessFrame()
|
||||||
|
{
|
||||||
|
Gpu.Fifo.DispatchCalls();
|
||||||
|
}
|
||||||
|
|
||||||
internal virtual void OnFinish(EventArgs e)
|
internal virtual void OnFinish(EventArgs e)
|
||||||
{
|
{
|
||||||
Finish?.Invoke(this, e);
|
Finish?.Invoke(this, e);
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace Ryujinx
|
||||||
private KeyboardState? Keyboard = null;
|
private KeyboardState? Keyboard = null;
|
||||||
|
|
||||||
private MouseState? Mouse = null;
|
private MouseState? Mouse = null;
|
||||||
|
|
||||||
public GLScreen(Switch Ns, IGalRenderer Renderer)
|
public GLScreen(Switch Ns, IGalRenderer Renderer)
|
||||||
: base(1280, 720,
|
: base(1280, 720,
|
||||||
new GraphicsMode(), "Ryujinx", 0,
|
new GraphicsMode(), "Ryujinx", 0,
|
||||||
|
@ -42,7 +42,7 @@ namespace Ryujinx
|
||||||
{
|
{
|
||||||
VSync = VSyncMode.On;
|
VSync = VSyncMode.On;
|
||||||
|
|
||||||
Renderer.SetWindowSize(Width, Height);
|
Renderer.FrameBuffer.SetWindowSize(Width, Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnUpdateFrame(FrameEventArgs e)
|
protected override void OnUpdateFrame(FrameEventArgs e)
|
||||||
|
@ -55,7 +55,7 @@ namespace Ryujinx
|
||||||
int LeftJoystickDY = 0;
|
int LeftJoystickDY = 0;
|
||||||
int RightJoystickDX = 0;
|
int RightJoystickDX = 0;
|
||||||
int RightJoystickDY = 0;
|
int RightJoystickDY = 0;
|
||||||
|
|
||||||
if (Keyboard.HasValue)
|
if (Keyboard.HasValue)
|
||||||
{
|
{
|
||||||
KeyboardState Keyboard = this.Keyboard.Value;
|
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.StickDown]) RightJoystickDY = -short.MaxValue;
|
||||||
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickLeft]) RightJoystickDX = -short.MaxValue;
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickLeft]) RightJoystickDX = -short.MaxValue;
|
||||||
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickRight]) RightJoystickDX = short.MaxValue;
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickRight]) RightJoystickDX = short.MaxValue;
|
||||||
|
|
||||||
//RightButtons
|
//RightButtons
|
||||||
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickButton]) CurrentButton |= HidControllerButtons.KEY_RSTICK;
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.StickButton]) CurrentButton |= HidControllerButtons.KEY_RSTICK;
|
||||||
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonA]) CurrentButton |= HidControllerButtons.KEY_A;
|
if (Keyboard[(Key)Config.FakeJoyCon.Right.ButtonA]) CurrentButton |= HidControllerButtons.KEY_A;
|
||||||
|
@ -179,28 +179,31 @@ namespace Ryujinx
|
||||||
CurrentButton,
|
CurrentButton,
|
||||||
LeftJoystick,
|
LeftJoystick,
|
||||||
RightJoystick);
|
RightJoystick);
|
||||||
|
|
||||||
|
Ns.ProcessFrame();
|
||||||
|
|
||||||
|
Renderer.RunActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnRenderFrame(FrameEventArgs e)
|
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.RecordSystemFrameTime();
|
||||||
$"{Ns.Statistics.GameFrameRate:0})";
|
|
||||||
|
|
||||||
Renderer.RunActions();
|
double HostFps = Ns.Statistics.GetSystemFrameRate();
|
||||||
Renderer.Render();
|
double GameFps = Ns.Statistics.GetGameFrameRate();
|
||||||
|
|
||||||
|
Title = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0}";
|
||||||
|
|
||||||
SwapBuffers();
|
SwapBuffers();
|
||||||
|
|
||||||
Ns.Statistics.EndSystemFrame();
|
|
||||||
|
|
||||||
Ns.Os.SignalVsync();
|
Ns.Os.SignalVsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnResize(EventArgs e)
|
protected override void OnResize(EventArgs e)
|
||||||
{
|
{
|
||||||
Renderer.SetWindowSize(Width, Height);
|
Renderer.FrameBuffer.SetWindowSize(Width, Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnKeyDown(KeyboardKeyEventArgs e)
|
protected override void OnKeyDown(KeyboardKeyEventArgs e)
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Ryujinx
|
||||||
{
|
{
|
||||||
Console.Title = "Ryujinx Console";
|
Console.Title = "Ryujinx Console";
|
||||||
|
|
||||||
IGalRenderer Renderer = new OpenGLRenderer();
|
IGalRenderer Renderer = new OGLRenderer();
|
||||||
|
|
||||||
IAalOutput AudioOut = new OpenALAudioOut();
|
IAalOutput AudioOut = new OpenALAudioOut();
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ namespace Ryujinx
|
||||||
Screen.Exit();
|
Screen.Exit();
|
||||||
};
|
};
|
||||||
|
|
||||||
Screen.Run(60.0);
|
Screen.Run(0.0, 60.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
|
|
Loading…
Reference in a new issue