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:
parent
8d83878f67
commit
416ddd0f6e
4 changed files with 97 additions and 72 deletions
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Reference in a new issue