forked from Mirror/Ryujinx
cd18ab29df
* Loop GLScreen with custom method * Fix deadlocks * Fix screen resizing * Change event to bool * Try to fix quitting error * Set title from main thread * Queue max 1 vsync, fix high FPS after a slowdown
423 lines
No EOL
17 KiB
C#
423 lines
No EOL
17 KiB
C#
using OpenTK;
|
|
using OpenTK.Graphics;
|
|
using OpenTK.Input;
|
|
using Ryujinx.Graphics.Gal;
|
|
using Ryujinx.HLE;
|
|
using Ryujinx.HLE.Input;
|
|
using System;
|
|
using System.Threading;
|
|
|
|
using Stopwatch = System.Diagnostics.Stopwatch;
|
|
|
|
namespace Ryujinx
|
|
{
|
|
public class GLScreen : GameWindow
|
|
{
|
|
private const int TouchScreenWidth = 1280;
|
|
private const int TouchScreenHeight = 720;
|
|
|
|
private const float TouchScreenRatioX = (float)TouchScreenWidth / TouchScreenHeight;
|
|
private const float TouchScreenRatioY = (float)TouchScreenHeight / TouchScreenWidth;
|
|
|
|
private const int TargetFPS = 60;
|
|
|
|
private Switch Ns;
|
|
|
|
private IGalRenderer Renderer;
|
|
|
|
private KeyboardState? Keyboard = null;
|
|
|
|
private MouseState? Mouse = null;
|
|
|
|
private Thread RenderThread;
|
|
|
|
private bool ResizeEvent;
|
|
|
|
private bool TitleEvent;
|
|
|
|
private string NewTitle;
|
|
|
|
public GLScreen(Switch Ns, IGalRenderer Renderer)
|
|
: base(1280, 720,
|
|
new GraphicsMode(), "Ryujinx", 0,
|
|
DisplayDevice.Default, 3, 3,
|
|
GraphicsContextFlags.ForwardCompatible)
|
|
{
|
|
this.Ns = Ns;
|
|
this.Renderer = Renderer;
|
|
|
|
Location = new Point(
|
|
(DisplayDevice.Default.Width / 2) - (Width / 2),
|
|
(DisplayDevice.Default.Height / 2) - (Height / 2));
|
|
|
|
ResizeEvent = false;
|
|
|
|
TitleEvent = false;
|
|
}
|
|
|
|
private void RenderLoop()
|
|
{
|
|
MakeCurrent();
|
|
|
|
Stopwatch Chrono = new Stopwatch();
|
|
|
|
Chrono.Start();
|
|
|
|
long TicksPerFrame = Stopwatch.Frequency / TargetFPS;
|
|
|
|
long Ticks = 0;
|
|
|
|
while (Exists && !IsExiting)
|
|
{
|
|
if (Ns.WaitFifo())
|
|
{
|
|
Ns.ProcessFrame();
|
|
}
|
|
|
|
Renderer.RunActions();
|
|
|
|
if (ResizeEvent)
|
|
{
|
|
ResizeEvent = false;
|
|
|
|
Renderer.FrameBuffer.SetWindowSize(Width, Height);
|
|
}
|
|
|
|
Ticks += Chrono.ElapsedTicks;
|
|
|
|
Chrono.Restart();
|
|
|
|
if (Ticks >= TicksPerFrame)
|
|
{
|
|
RenderFrame();
|
|
|
|
//Queue max. 1 vsync
|
|
Ticks = Math.Min(Ticks - TicksPerFrame, TicksPerFrame);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void MainLoop()
|
|
{
|
|
VSync = VSyncMode.Off;
|
|
|
|
Visible = true;
|
|
|
|
Renderer.FrameBuffer.SetWindowSize(Width, Height);
|
|
|
|
Context.MakeCurrent(null);
|
|
|
|
//OpenTK doesn't like sleeps in its thread, to avoid this a renderer thread is created
|
|
RenderThread = new Thread(RenderLoop);
|
|
|
|
RenderThread.Start();
|
|
|
|
while (Exists && !IsExiting)
|
|
{
|
|
ProcessEvents();
|
|
|
|
if (!IsExiting)
|
|
{
|
|
UpdateFrame();
|
|
|
|
if (TitleEvent)
|
|
{
|
|
TitleEvent = false;
|
|
|
|
Title = NewTitle;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool IsGamePadButtonPressedFromString(GamePadState GamePad, string Button)
|
|
{
|
|
if (Button.ToUpper() == "LTRIGGER" || Button.ToUpper() == "RTRIGGER")
|
|
{
|
|
return GetGamePadTriggerFromString(GamePad, Button) >= Config.GamePadTriggerThreshold;
|
|
}
|
|
else
|
|
{
|
|
return (GetGamePadButtonFromString(GamePad, Button) == ButtonState.Pressed);
|
|
}
|
|
}
|
|
|
|
private ButtonState GetGamePadButtonFromString(GamePadState GamePad, string Button)
|
|
{
|
|
switch (Button.ToUpper())
|
|
{
|
|
case "A": return GamePad.Buttons.A;
|
|
case "B": return GamePad.Buttons.B;
|
|
case "X": return GamePad.Buttons.X;
|
|
case "Y": return GamePad.Buttons.Y;
|
|
case "LSTICK": return GamePad.Buttons.LeftStick;
|
|
case "RSTICK": return GamePad.Buttons.RightStick;
|
|
case "LSHOULDER": return GamePad.Buttons.LeftShoulder;
|
|
case "RSHOULDER": return GamePad.Buttons.RightShoulder;
|
|
case "DPADUP": return GamePad.DPad.Up;
|
|
case "DPADDOWN": return GamePad.DPad.Down;
|
|
case "DPADLEFT": return GamePad.DPad.Left;
|
|
case "DPADRIGHT": return GamePad.DPad.Right;
|
|
case "START": return GamePad.Buttons.Start;
|
|
case "BACK": return GamePad.Buttons.Back;
|
|
default: throw new ArgumentException();
|
|
}
|
|
}
|
|
|
|
private float GetGamePadTriggerFromString(GamePadState GamePad, string Trigger)
|
|
{
|
|
switch (Trigger.ToUpper())
|
|
{
|
|
case "LTRIGGER": return GamePad.Triggers.Left;
|
|
case "RTRIGGER": return GamePad.Triggers.Right;
|
|
default: throw new ArgumentException();
|
|
}
|
|
}
|
|
|
|
private Vector2 GetJoystickAxisFromString(GamePadState GamePad, string Joystick)
|
|
{
|
|
switch (Joystick.ToUpper())
|
|
{
|
|
case "LJOYSTICK": return GamePad.ThumbSticks.Left;
|
|
case "RJOYSTICK": return new Vector2(-GamePad.ThumbSticks.Right.Y, -GamePad.ThumbSticks.Right.X);
|
|
default: throw new ArgumentException();
|
|
}
|
|
}
|
|
|
|
private new void UpdateFrame()
|
|
{
|
|
HidControllerButtons CurrentButton = 0;
|
|
HidJoystickPosition LeftJoystick;
|
|
HidJoystickPosition RightJoystick;
|
|
|
|
int LeftJoystickDX = 0;
|
|
int LeftJoystickDY = 0;
|
|
int RightJoystickDX = 0;
|
|
int RightJoystickDY = 0;
|
|
float AnalogStickDeadzone = Config.GamePadDeadzone;
|
|
|
|
//Keyboard Input
|
|
if (Keyboard.HasValue)
|
|
{
|
|
KeyboardState Keyboard = this.Keyboard.Value;
|
|
|
|
if (Keyboard[Key.Escape]) this.Exit();
|
|
|
|
//LeftJoystick
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickUp]) LeftJoystickDY = short.MaxValue;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickDown]) LeftJoystickDY = -short.MaxValue;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickLeft]) LeftJoystickDX = -short.MaxValue;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickRight]) LeftJoystickDX = short.MaxValue;
|
|
|
|
//LeftButtons
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickButton]) CurrentButton |= HidControllerButtons.KEY_LSTICK;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.DPadUp]) CurrentButton |= HidControllerButtons.KEY_DUP;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.DPadDown]) CurrentButton |= HidControllerButtons.KEY_DDOWN;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.DPadLeft]) CurrentButton |= HidControllerButtons.KEY_DLEFT;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.DPadRight]) CurrentButton |= HidControllerButtons.KEY_DRIGHT;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.ButtonMinus]) CurrentButton |= HidControllerButtons.KEY_MINUS;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.ButtonL]) CurrentButton |= HidControllerButtons.KEY_L;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.ButtonZL]) CurrentButton |= HidControllerButtons.KEY_ZL;
|
|
|
|
//RightJoystick
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickUp]) RightJoystickDY = short.MaxValue;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickDown]) RightJoystickDY = -short.MaxValue;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickLeft]) RightJoystickDX = -short.MaxValue;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickRight]) RightJoystickDX = short.MaxValue;
|
|
|
|
//RightButtons
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickButton]) CurrentButton |= HidControllerButtons.KEY_RSTICK;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonA]) CurrentButton |= HidControllerButtons.KEY_A;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonB]) CurrentButton |= HidControllerButtons.KEY_B;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonX]) CurrentButton |= HidControllerButtons.KEY_X;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonY]) CurrentButton |= HidControllerButtons.KEY_Y;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonPlus]) CurrentButton |= HidControllerButtons.KEY_PLUS;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonR]) CurrentButton |= HidControllerButtons.KEY_R;
|
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonZR]) CurrentButton |= HidControllerButtons.KEY_ZR;
|
|
}
|
|
|
|
//Controller Input
|
|
if (Config.GamePadEnable)
|
|
{
|
|
GamePadState GamePad = OpenTK.Input.GamePad.GetState(Config.GamePadIndex);
|
|
//LeftButtons
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.DPadUp)) CurrentButton |= HidControllerButtons.KEY_DUP;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.DPadDown)) CurrentButton |= HidControllerButtons.KEY_DDOWN;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.DPadLeft)) CurrentButton |= HidControllerButtons.KEY_DLEFT;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.DPadRight)) CurrentButton |= HidControllerButtons.KEY_DRIGHT;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.StickButton)) CurrentButton |= HidControllerButtons.KEY_LSTICK;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.ButtonMinus)) CurrentButton |= HidControllerButtons.KEY_MINUS;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.ButtonL)) CurrentButton |= HidControllerButtons.KEY_L;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.ButtonZL)) CurrentButton |= HidControllerButtons.KEY_ZL;
|
|
|
|
//RightButtons
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonA)) CurrentButton |= HidControllerButtons.KEY_A;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonB)) CurrentButton |= HidControllerButtons.KEY_B;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonX)) CurrentButton |= HidControllerButtons.KEY_X;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonY)) CurrentButton |= HidControllerButtons.KEY_Y;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.StickButton)) CurrentButton |= HidControllerButtons.KEY_RSTICK;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonPlus)) CurrentButton |= HidControllerButtons.KEY_PLUS;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonR)) CurrentButton |= HidControllerButtons.KEY_R;
|
|
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonZR)) CurrentButton |= HidControllerButtons.KEY_ZR;
|
|
|
|
//LeftJoystick
|
|
if (GetJoystickAxisFromString(GamePad, Config.JoyConController.Left.Stick).X >= AnalogStickDeadzone
|
|
|| GetJoystickAxisFromString(GamePad, Config.JoyConController.Left.Stick).X <= -AnalogStickDeadzone)
|
|
LeftJoystickDX = (int)(GetJoystickAxisFromString(GamePad, Config.JoyConController.Left.Stick).X * short.MaxValue);
|
|
|
|
if (GetJoystickAxisFromString(GamePad, Config.JoyConController.Left.Stick).Y >= AnalogStickDeadzone
|
|
|| GetJoystickAxisFromString(GamePad, Config.JoyConController.Left.Stick).Y <= -AnalogStickDeadzone)
|
|
LeftJoystickDY = (int)(GetJoystickAxisFromString(GamePad, Config.JoyConController.Left.Stick).Y * short.MaxValue);
|
|
|
|
//RightJoystick
|
|
if (GetJoystickAxisFromString(GamePad, Config.JoyConController.Right.Stick).X >= AnalogStickDeadzone
|
|
|| GetJoystickAxisFromString(GamePad, Config.JoyConController.Right.Stick).X <= -AnalogStickDeadzone)
|
|
RightJoystickDX = (int)(GetJoystickAxisFromString(GamePad, Config.JoyConController.Right.Stick).X * short.MaxValue);
|
|
|
|
if (GetJoystickAxisFromString(GamePad, Config.JoyConController.Right.Stick).Y >= AnalogStickDeadzone
|
|
|| GetJoystickAxisFromString(GamePad, Config.JoyConController.Right.Stick).Y <= -AnalogStickDeadzone)
|
|
RightJoystickDY = (int)(GetJoystickAxisFromString(GamePad, Config.JoyConController.Right.Stick).Y * short.MaxValue);
|
|
}
|
|
|
|
LeftJoystick = new HidJoystickPosition
|
|
{
|
|
DX = LeftJoystickDX,
|
|
DY = LeftJoystickDY
|
|
};
|
|
|
|
RightJoystick = new HidJoystickPosition
|
|
{
|
|
DX = RightJoystickDX,
|
|
DY = RightJoystickDY
|
|
};
|
|
|
|
bool HasTouch = false;
|
|
|
|
//Get screen touch position from left mouse click
|
|
//OpenTK always captures mouse events, even if out of focus, so check if window is focused.
|
|
if (Focused && Mouse?.LeftButton == ButtonState.Pressed)
|
|
{
|
|
MouseState Mouse = this.Mouse.Value;
|
|
|
|
int ScrnWidth = Width;
|
|
int ScrnHeight = Height;
|
|
|
|
if (Width > Height * TouchScreenRatioX)
|
|
{
|
|
ScrnWidth = (int)(Height * TouchScreenRatioX);
|
|
}
|
|
else
|
|
{
|
|
ScrnHeight = (int)(Width * TouchScreenRatioY);
|
|
}
|
|
|
|
int StartX = (Width - ScrnWidth) >> 1;
|
|
int StartY = (Height - ScrnHeight) >> 1;
|
|
|
|
int EndX = StartX + ScrnWidth;
|
|
int EndY = StartY + ScrnHeight;
|
|
|
|
if (Mouse.X >= StartX &&
|
|
Mouse.Y >= StartY &&
|
|
Mouse.X < EndX &&
|
|
Mouse.Y < EndY)
|
|
{
|
|
int ScrnMouseX = Mouse.X - StartX;
|
|
int ScrnMouseY = Mouse.Y - StartY;
|
|
|
|
int MX = (int)(((float)ScrnMouseX / ScrnWidth) * TouchScreenWidth);
|
|
int MY = (int)(((float)ScrnMouseY / ScrnHeight) * TouchScreenHeight);
|
|
|
|
HidTouchPoint CurrentPoint = new HidTouchPoint
|
|
{
|
|
X = MX,
|
|
Y = MY,
|
|
|
|
//Placeholder values till more data is acquired
|
|
DiameterX = 10,
|
|
DiameterY = 10,
|
|
Angle = 90
|
|
};
|
|
|
|
HasTouch = true;
|
|
|
|
Ns.Hid.SetTouchPoints(CurrentPoint);
|
|
}
|
|
}
|
|
|
|
if (!HasTouch)
|
|
{
|
|
Ns.Hid.SetTouchPoints();
|
|
}
|
|
|
|
Ns.Hid.SetJoyconButton(
|
|
HidControllerId.CONTROLLER_HANDHELD,
|
|
HidControllerLayouts.Handheld_Joined,
|
|
CurrentButton,
|
|
LeftJoystick,
|
|
RightJoystick);
|
|
|
|
Ns.Hid.SetJoyconButton(
|
|
HidControllerId.CONTROLLER_HANDHELD,
|
|
HidControllerLayouts.Main,
|
|
CurrentButton,
|
|
LeftJoystick,
|
|
RightJoystick);
|
|
}
|
|
|
|
private new void RenderFrame()
|
|
{
|
|
Renderer.FrameBuffer.Render();
|
|
|
|
Ns.Statistics.RecordSystemFrameTime();
|
|
|
|
double HostFps = Ns.Statistics.GetSystemFrameRate();
|
|
double GameFps = Ns.Statistics.GetGameFrameRate();
|
|
|
|
NewTitle = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0}";
|
|
|
|
TitleEvent = true;
|
|
|
|
SwapBuffers();
|
|
|
|
Ns.Os.SignalVsync();
|
|
}
|
|
|
|
protected override void OnUnload(EventArgs e)
|
|
{
|
|
RenderThread.Join();
|
|
|
|
base.OnUnload(e);
|
|
}
|
|
|
|
protected override void OnResize(EventArgs e)
|
|
{
|
|
ResizeEvent = true;
|
|
}
|
|
|
|
protected override void OnKeyDown(KeyboardKeyEventArgs e)
|
|
{
|
|
Keyboard = e.Keyboard;
|
|
}
|
|
|
|
protected override void OnKeyUp(KeyboardKeyEventArgs e)
|
|
{
|
|
Keyboard = e.Keyboard;
|
|
}
|
|
|
|
protected override void OnMouseDown(MouseButtonEventArgs e)
|
|
{
|
|
Mouse = e.Mouse;
|
|
}
|
|
|
|
protected override void OnMouseUp(MouseButtonEventArgs e)
|
|
{
|
|
Mouse = e.Mouse;
|
|
}
|
|
|
|
protected override void OnMouseMove(MouseMoveEventArgs e)
|
|
{
|
|
Mouse = e.Mouse;
|
|
}
|
|
}
|
|
} |