Some fixes for the new GLRenderer (#930)

* Some fixes for the new GLRenderer

Changelog:
- Fix transparency of the window on some games on Windows.
- Fix escape key not being able to exit emulation.
- Fix inverted logic in fullscreen event handling.
- Fix a race condition when stoping emulation causing a hang.
- Fix a memory leak of the OpenGL context when stoping emulation (saving ~200MB of RAM when stoping emulation).
- Simplify and document behaviours when exiting the emulator while the
emulation is running.

* Make sure to clear alpha channel when presenting Texture

This fix once and for all the transparency issue on Windows.

* Enforce footer bar size to avoid gl widget to get resized to 1280x724

* Fix full screen inversion in MainWindow and make sure _listStatusBox don't come back when not needed

* Remove previous transparency clear attempt that is useless now

* Remove an extra line return
This commit is contained in:
Thog 2020-02-13 18:43:29 +01:00 committed by GitHub
parent 8d83878f67
commit 416ddd0f6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 97 additions and 72 deletions

View file

@ -22,15 +22,30 @@ namespace Ryujinx.Graphics.OpenGL
public void Present(ITexture texture, ImageCrop crop) public void Present(ITexture texture, ImageCrop crop)
{ {
TextureView view = (TextureView)texture;
GL.Disable(EnableCap.FramebufferSrgb); GL.Disable(EnableCap.FramebufferSrgb);
CopyTextureToFrameBufferRGB(0, GetCopyFramebufferHandleLazy(), (TextureView)texture, crop);
GL.Enable(EnableCap.FramebufferSrgb);
}
public void SetSize(int width, int height)
{
_width = width;
_height = height;
}
private void CopyTextureToFrameBufferRGB(int drawFramebuffer, int readFramebuffer, TextureView view, ImageCrop crop)
{
bool[] oldFramebufferColorWritemask = new bool[4];
int oldReadFramebufferHandle = GL.GetInteger(GetPName.ReadFramebufferBinding); int oldReadFramebufferHandle = GL.GetInteger(GetPName.ReadFramebufferBinding);
int oldDrawFramebufferHandle = GL.GetInteger(GetPName.DrawFramebufferBinding); int oldDrawFramebufferHandle = GL.GetInteger(GetPName.DrawFramebufferBinding);
GL.GetBoolean(GetIndexedPName.ColorWritemask, drawFramebuffer, oldFramebufferColorWritemask);
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0); GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, drawFramebuffer);
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetCopyFramebufferHandleLazy()); GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, readFramebuffer);
GL.FramebufferTexture( GL.FramebufferTexture(
FramebufferTarget.ReadFramebuffer, FramebufferTarget.ReadFramebuffer,
@ -93,16 +108,17 @@ namespace Ryujinx.Graphics.OpenGL
ClearBufferMask.ColorBufferBit, ClearBufferMask.ColorBufferBit,
BlitFramebufferFilter.Linear); BlitFramebufferFilter.Linear);
// Remove Alpha channel
GL.ColorMask(drawFramebuffer, false, false, false, true);
GL.ClearBuffer(ClearBuffer.Color, 0, new float[] { 0.0f, 0.0f, 0.0f, 1.0f });
GL.ColorMask(drawFramebuffer,
oldFramebufferColorWritemask[0],
oldFramebufferColorWritemask[1],
oldFramebufferColorWritemask[2],
oldFramebufferColorWritemask[3]);
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle); GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, oldReadFramebufferHandle);
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle); GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, oldDrawFramebufferHandle);
GL.Enable(EnableCap.FramebufferSrgb);
}
public void SetSize(int width, int height)
{
_width = width;
_height = height;
} }
private int GetCopyFramebufferHandleLazy() private int GetCopyFramebufferHandleLazy()

View file

@ -53,7 +53,7 @@ namespace Ryujinx.Ui
private Input.NpadController _primaryController; private Input.NpadController _primaryController;
public GLRenderer(Switch device) public GLRenderer(Switch device)
: base (new GraphicsMode(new ColorFormat(24)), : base (new GraphicsMode(new ColorFormat()),
3, 3, 3, 3,
GraphicsContextFlags.ForwardCompatible) GraphicsContextFlags.ForwardCompatible)
{ {
@ -63,6 +63,7 @@ namespace Ryujinx.Ui
this.Initialized += GLRenderer_Initialized; this.Initialized += GLRenderer_Initialized;
this.Destroyed += GLRenderer_Destroyed; this.Destroyed += GLRenderer_Destroyed;
this.ShuttingDown += GLRenderer_ShuttingDown;
Initialize(); Initialize();
@ -81,6 +82,11 @@ namespace Ryujinx.Ui
this.Shown += Renderer_Shown; this.Shown += Renderer_Shown;
} }
private void GLRenderer_ShuttingDown(object sender, EventArgs args)
{
Exit();
}
private void Parent_FocusOutEvent(object o, Gtk.FocusOutEventArgs args) private void Parent_FocusOutEvent(object o, Gtk.FocusOutEventArgs args)
{ {
IsFocused = false; IsFocused = false;
@ -93,9 +99,7 @@ namespace Ryujinx.Ui
private void GLRenderer_Destroyed(object sender, EventArgs e) private void GLRenderer_Destroyed(object sender, EventArgs e)
{ {
Exit(); Dispose();
this.Dispose();
} }
protected void Renderer_Shown(object sender, EventArgs e) protected void Renderer_Shown(object sender, EventArgs e)
@ -106,41 +110,38 @@ namespace Ryujinx.Ui
public void HandleScreenState(KeyboardState keyboard) public void HandleScreenState(KeyboardState keyboard)
{ {
bool toggleFullscreen = keyboard.IsKeyDown(OpenTK.Input.Key.F11) bool toggleFullscreen = keyboard.IsKeyDown(OpenTK.Input.Key.F11)
|| ((keyboard.IsKeyDown(OpenTK.Input.Key.AltLeft) || ((keyboard.IsKeyDown(OpenTK.Input.Key.AltLeft)
|| keyboard.IsKeyDown(OpenTK.Input.Key.AltRight)) || keyboard.IsKeyDown(OpenTK.Input.Key.AltRight))
&& keyboard.IsKeyDown(OpenTK.Input.Key.Enter)); && keyboard.IsKeyDown(OpenTK.Input.Key.Enter))
|| keyboard.IsKeyDown(OpenTK.Input.Key.Escape);
if (toggleFullscreen == _toggleFullscreen) bool fullScreenToggled = ParentWindow.State.HasFlag(Gdk.WindowState.Fullscreen);
if (toggleFullscreen != _toggleFullscreen)
{ {
return; if (toggleFullscreen)
{
if (fullScreenToggled)
{
ParentWindow.Unfullscreen();
(Toplevel as MainWindow)?.ToggleExtraWidgets(true);
}
else
{
if (keyboard.IsKeyDown(OpenTK.Input.Key.Escape))
{
Exit();
}
else
{
ParentWindow.Fullscreen();
(Toplevel as MainWindow)?.ToggleExtraWidgets(false);
}
}
}
} }
_toggleFullscreen = toggleFullscreen; _toggleFullscreen = toggleFullscreen;
Gtk.Application.Invoke(delegate
{
if (this.ParentWindow.State.HasFlag(Gdk.WindowState.Fullscreen))
{
if (keyboard.IsKeyDown(OpenTK.Input.Key.Escape) || _toggleFullscreen)
{
this.ParentWindow.Unfullscreen();
(this.Toplevel as MainWindow)?.ToggleExtraWidgets(true);
}
}
else
{
if (keyboard.IsKeyDown(OpenTK.Input.Key.Escape))
{
Exit();
}
if (_toggleFullscreen)
{
this.ParentWindow.Fullscreen();
(this.Toplevel as MainWindow)?.ToggleExtraWidgets(false);
}
}
});
} }
private void GLRenderer_Initialized(object sender, EventArgs e) private void GLRenderer_Initialized(object sender, EventArgs e)

View file

@ -31,7 +31,7 @@ namespace Ryujinx.Ui
private static GLRenderer _gLWidget; private static GLRenderer _gLWidget;
private static AutoResetEvent _screenExitStatus = new AutoResetEvent(false); private static AutoResetEvent _deviceExitStatus = new AutoResetEvent(false);
private static ListStore _tableStore; private static ListStore _tableStore;
@ -356,7 +356,7 @@ namespace Ryujinx.Ui
_emulationContext = device; _emulationContext = device;
_screenExitStatus.Reset(); _deviceExitStatus.Reset();
#if MACOS_BUILD #if MACOS_BUILD
CreateGameWindow(device); CreateGameWindow(device);
@ -391,8 +391,6 @@ namespace Ryujinx.Ui
{ {
device.Hid.InitializePrimaryController(ConfigurationState.Instance.Hid.ControllerType); device.Hid.InitializePrimaryController(ConfigurationState.Instance.Hid.ControllerType);
_gLWidget?.Exit();
_gLWidget?.Dispose();
_gLWidget = new GLRenderer(_emulationContext); _gLWidget = new GLRenderer(_emulationContext);
Application.Invoke(delegate Application.Invoke(delegate
@ -402,13 +400,17 @@ namespace Ryujinx.Ui
_viewBox.Child = _gLWidget; _viewBox.Child = _gLWidget;
_gLWidget.ShowAll(); _gLWidget.ShowAll();
_listStatusBox.Hide(); ClearFooterForGameRender();
}); });
_gLWidget.WaitEvent.WaitOne(); _gLWidget.WaitEvent.WaitOne();
_gLWidget.Start(); _gLWidget.Start();
device.Dispose();
_deviceExitStatus.Set();
// NOTE: Everything that is here will not be executed when you close the UI.
Application.Invoke(delegate Application.Invoke(delegate
{ {
_viewBox.Remove(_gLWidget); _viewBox.Remove(_gLWidget);
@ -419,36 +421,41 @@ namespace Ryujinx.Ui
_gLWidget.Window.Dispose(); _gLWidget.Window.Dispose();
} }
_gLWidget.Dispose();
_viewBox.Add(_gameTableWindow); _viewBox.Add(_gameTableWindow);
_gameTableWindow.Expand = true; _gameTableWindow.Expand = true;
this.Window.Title = "Ryujinx"; this.Window.Title = "Ryujinx";
_listStatusBox.ShowAll(); _emulationContext = null;
_gameLoaded = false;
_gLWidget = null;
DiscordIntegrationModule.SwitchToMainMenu();
RecreateFooterForMenu();
UpdateColumns(); UpdateColumns();
UpdateGameTable(); UpdateGameTable();
Task.Run(RefreshFirmwareLabel); Task.Run(RefreshFirmwareLabel);
});
device.Dispose();
_emulationContext = null;
_gameLoaded = false;
_gLWidget = null;
DiscordIntegrationModule.SwitchToMainMenu();
Application.Invoke(delegate
{
_stopEmulation.Sensitive = false; _stopEmulation.Sensitive = false;
_firmwareInstallFile.Sensitive = true; _firmwareInstallFile.Sensitive = true;
_firmwareInstallDirectory.Sensitive = true; _firmwareInstallDirectory.Sensitive = true;
}); });
}
_screenExitStatus.Set(); private void RecreateFooterForMenu()
{
_footerBox.Add(_listStatusBox);
}
private void ClearFooterForGameRender()
{
_footerBox.Remove(_listStatusBox);
} }
public void ToggleExtraWidgets(bool show) public void ToggleExtraWidgets(bool show)
@ -469,7 +476,7 @@ namespace Ryujinx.Ui
bool fullScreenToggled = this.Window.State.HasFlag(Gdk.WindowState.Fullscreen); bool fullScreenToggled = this.Window.State.HasFlag(Gdk.WindowState.Fullscreen);
_fullScreen.Label = !fullScreenToggled ? "Exit Fullscreen" : "Enter Fullscreen"; _fullScreen.Label = fullScreenToggled ? "Exit Fullscreen" : "Enter Fullscreen";
} }
private static void UpdateGameMetadata(string titleId) private static void UpdateGameMetadata(string titleId)
@ -506,8 +513,11 @@ namespace Ryujinx.Ui
if (_gLWidget != null) if (_gLWidget != null)
{ {
// We tell the widget that we are exiting
_gLWidget.Exit(); _gLWidget.Exit();
_screenExitStatus.WaitOne();
// Wait for the other thread to dispose the HLE context before exiting.
_deviceExitStatus.WaitOne();
} }
} }
@ -874,16 +884,12 @@ namespace Ryujinx.Ui
{ {
Fullscreen(); Fullscreen();
_fullScreen.Label = "Exit Fullscreen";
ToggleExtraWidgets(false); ToggleExtraWidgets(false);
} }
else else
{ {
Unfullscreen(); Unfullscreen();
_fullScreen.Label = "Enter Fullscreen";
ToggleExtraWidgets(true); ToggleExtraWidgets(true);
} }
} }

View file

@ -7,7 +7,7 @@
<property name="title" translatable="yes">Ryujinx</property> <property name="title" translatable="yes">Ryujinx</property>
<property name="window_position">center</property> <property name="window_position">center</property>
<property name="default_width">1280</property> <property name="default_width">1280</property>
<property name="default_height">750</property> <property name="default_height">760</property>
<child type="titlebar"> <child type="titlebar">
<placeholder/> <placeholder/>
</child> </child>
@ -357,7 +357,7 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkBox" id="MainBox"> <object class="GtkBox" id="_mainBox">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
@ -403,6 +403,8 @@
<object class="GtkBox" id="_footerBox"> <object class="GtkBox" id="_footerBox">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="width_request">1280</property>
<property name="height_request">19</property>
<child> <child>
<object class="GtkBox" id="_listStatusBox"> <object class="GtkBox" id="_listStatusBox">
<property name="visible">True</property> <property name="visible">True</property>