rjx-mirror/Ryujinx/Ui/GLScreen.cs
emmauss db1a759c59 Lock GbpQueueBuffer till Vsync is signalled (#367)
* Initial Framerate limit implementation

* use seperate event for limiter

* check for vsync signal after queue up framebuffer

* removed ingame toggle

* fix nits
2018-09-10 01:38:56 +02:00

333 lines
No EOL
9.1 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 int TargetFPS = 60;
private Switch Device;
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 Device, IGalRenderer Renderer)
: base(1280, 720,
new GraphicsMode(), "Ryujinx", 0,
DisplayDevice.Default, 3, 3,
GraphicsContextFlags.ForwardCompatible)
{
this.Device = Device;
this.Renderer = Renderer;
Location = new Point(
(DisplayDevice.Default.Width / 2) - (Width / 2),
(DisplayDevice.Default.Height / 2) - (Height / 2));
}
private void RenderLoop()
{
MakeCurrent();
Stopwatch Chrono = new Stopwatch();
Chrono.Start();
long TicksPerFrame = Stopwatch.Frequency / TargetFPS;
long Ticks = 0;
while (Exists && !IsExiting)
{
if (Device.WaitFifo())
{
Device.ProcessFrame();
}
Renderer.RunActions();
if (ResizeEvent)
{
ResizeEvent = false;
Renderer.RenderTarget.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.RenderTarget.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;
}
}
//Polling becomes expensive if it's not slept
Thread.Sleep(1);
}
}
private new void UpdateFrame()
{
HidControllerButtons CurrentButton = 0;
HidJoystickPosition LeftJoystick;
HidJoystickPosition RightJoystick;
int LeftJoystickDX = 0;
int LeftJoystickDY = 0;
int RightJoystickDX = 0;
int RightJoystickDY = 0;
//Keyboard Input
if (Keyboard.HasValue)
{
KeyboardState Keyboard = this.Keyboard.Value;
CurrentButton = Config.JoyConKeyboard.GetButtons(Keyboard);
(LeftJoystickDX, LeftJoystickDY) = Config.JoyConKeyboard.GetLeftStick(Keyboard);
(RightJoystickDX, RightJoystickDY) = Config.JoyConKeyboard.GetRightStick(Keyboard);
}
//Controller Input
CurrentButton |= Config.JoyConController.GetButtons();
//Keyboard has priority stick-wise
if (LeftJoystickDX == 0 && LeftJoystickDY == 0)
{
(LeftJoystickDX, LeftJoystickDY) = Config.JoyConController.GetLeftStick();
}
if (RightJoystickDX == 0 && RightJoystickDY == 0)
{
(RightJoystickDX, RightJoystickDY) = Config.JoyConController.GetRightStick();
}
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 * TouchScreenWidth) / TouchScreenHeight)
{
ScrnWidth = (Height * TouchScreenWidth) / TouchScreenHeight;
}
else
{
ScrnHeight = (Width * TouchScreenHeight) / TouchScreenWidth;
}
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 = (ScrnMouseX * TouchScreenWidth) / ScrnWidth;
int MY = (ScrnMouseY * TouchScreenHeight) / ScrnHeight;
HidTouchPoint CurrentPoint = new HidTouchPoint
{
X = MX,
Y = MY,
//Placeholder values till more data is acquired
DiameterX = 10,
DiameterY = 10,
Angle = 90
};
HasTouch = true;
Device.Hid.SetTouchPoints(CurrentPoint);
}
}
if (!HasTouch)
{
Device.Hid.SetTouchPoints();
}
Device.Hid.SetJoyconButton(
HidControllerId.CONTROLLER_HANDHELD,
HidControllerLayouts.Handheld_Joined,
CurrentButton,
LeftJoystick,
RightJoystick);
Device.Hid.SetJoyconButton(
HidControllerId.CONTROLLER_HANDHELD,
HidControllerLayouts.Main,
CurrentButton,
LeftJoystick,
RightJoystick);
}
private new void RenderFrame()
{
Renderer.RenderTarget.Render();
Device.Statistics.RecordSystemFrameTime();
double HostFps = Device.Statistics.GetSystemFrameRate();
double GameFps = Device.Statistics.GetGameFrameRate();
NewTitle = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0} | Game Vsync: " +
(Device.EnableDeviceVsync ? "On" : "Off");
TitleEvent = true;
SwapBuffers();
Device.System.SignalVsync();
Device.VsyncEvent.Set();
}
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)
{
bool ToggleFullscreen = e.Key == Key.F11 ||
(e.Modifiers.HasFlag(KeyModifiers.Alt) && e.Key == Key.Enter);
if (WindowState == WindowState.Fullscreen)
{
if (e.Key == Key.Escape || ToggleFullscreen)
{
WindowState = WindowState.Normal;
}
}
else
{
if (e.Key == Key.Escape)
{
Exit();
}
if (ToggleFullscreen)
{
WindowState = WindowState.Fullscreen;
}
}
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;
}
}
}