support loading and closing games
This commit is contained in:
parent
f48c0e91a5
commit
7cdd401322
12 changed files with 413 additions and 135 deletions
|
@ -8,6 +8,8 @@ namespace Ryujinx.Graphics.Gal
|
||||||
|
|
||||||
void RunActions();
|
void RunActions();
|
||||||
|
|
||||||
|
void ClearActions();
|
||||||
|
|
||||||
IGalConstBuffer Buffer { get; }
|
IGalConstBuffer Buffer { get; }
|
||||||
|
|
||||||
IGalRenderTarget RenderTarget { get; }
|
IGalRenderTarget RenderTarget { get; }
|
||||||
|
|
|
@ -50,5 +50,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
RenderAction();
|
RenderAction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ClearActions()
|
||||||
|
{
|
||||||
|
ActionsQueue.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics
|
namespace Ryujinx.Graphics
|
||||||
{
|
{
|
||||||
public class NvGpu
|
public class NvGpu : IDisposable
|
||||||
{
|
{
|
||||||
public IGalRenderer Renderer { get; private set; }
|
public IGalRenderer Renderer { get; private set; }
|
||||||
|
|
||||||
|
@ -28,5 +29,15 @@ namespace Ryujinx.Graphics
|
||||||
EngineM2mf = new NvGpuEngineM2mf(this);
|
EngineM2mf = new NvGpuEngineM2mf(this);
|
||||||
EngineP2mf = new NvGpuEngineP2mf(this);
|
EngineP2mf = new NvGpuEngineP2mf(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool Disposing)
|
||||||
|
{
|
||||||
|
Fifo.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
using Ryujinx.Graphics.Memory;
|
using Ryujinx.Graphics.Memory;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics
|
namespace Ryujinx.Graphics
|
||||||
{
|
{
|
||||||
public class NvGpuFifo
|
public class NvGpuFifo : IDisposable
|
||||||
{
|
{
|
||||||
private const int MacrosCount = 0x80;
|
private const int MacrosCount = 0x80;
|
||||||
private const int MacroIndexMask = MacrosCount - 1;
|
private const int MacroIndexMask = MacrosCount - 1;
|
||||||
|
@ -199,5 +200,15 @@ namespace Ryujinx.Graphics
|
||||||
{
|
{
|
||||||
Gpu.EngineM2mf.CallMethod(Vmm, PBEntry);
|
Gpu.EngineM2mf.CallMethod(Vmm, PBEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool Disposing)
|
||||||
|
{
|
||||||
|
BufferQueue.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -120,6 +120,8 @@ namespace Ryujinx.HLE
|
||||||
System.Dispose();
|
System.Dispose();
|
||||||
|
|
||||||
VsyncEvent.Dispose();
|
VsyncEvent.Dispose();
|
||||||
|
|
||||||
|
Gpu.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
206
Ryujinx.UI/Emulation/EmulationController.cs
Normal file
206
Ryujinx.UI/Emulation/EmulationController.cs
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
using Qml.Net;
|
||||||
|
using Ryujinx.Audio;
|
||||||
|
using Ryujinx.Audio.OpenAL;
|
||||||
|
using Ryujinx.Graphics.Gal;
|
||||||
|
using Ryujinx.Graphics.Gal.OpenGL;
|
||||||
|
using Ryujinx.HLE;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI.Emulation
|
||||||
|
{
|
||||||
|
[Signal("failed", NetVariantType.String)]
|
||||||
|
[Signal("success")]
|
||||||
|
[Signal("loaded")]
|
||||||
|
[Signal("unloaded")]
|
||||||
|
class EmulationController
|
||||||
|
{
|
||||||
|
private static GLScreen RenderScreen;
|
||||||
|
private static Switch Device;
|
||||||
|
private static IAalOutput AudioOut;
|
||||||
|
private static IGalRenderer Renderer;
|
||||||
|
|
||||||
|
private bool IsClosing;
|
||||||
|
|
||||||
|
private bool isLoaded;
|
||||||
|
|
||||||
|
public bool IsLoaded
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return isLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
isLoaded = value;
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
this.ActivateSignal("loaded");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.ActivateSignal("unloaded");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmulationController()
|
||||||
|
{
|
||||||
|
RenderScreen = null;
|
||||||
|
Device = null;
|
||||||
|
AudioOut = null;
|
||||||
|
|
||||||
|
IsLoaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void LoadGameFile(string GameFile)
|
||||||
|
{
|
||||||
|
GameFile = GameFile.Replace("file:///", string.Empty);
|
||||||
|
|
||||||
|
if (!File.Exists(GameFile))
|
||||||
|
{
|
||||||
|
this.ActivateSignal("failed", $"File {GameFile} does not exist.");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShutdownEmulation();
|
||||||
|
|
||||||
|
InitializeEmulator();
|
||||||
|
|
||||||
|
switch (Path.GetExtension(GameFile).ToLowerInvariant())
|
||||||
|
{
|
||||||
|
case ".xci":
|
||||||
|
Console.WriteLine("Loading as XCI.");
|
||||||
|
Device.LoadXci(GameFile);
|
||||||
|
break;
|
||||||
|
case ".nca":
|
||||||
|
Console.WriteLine("Loading as NCA.");
|
||||||
|
Device.LoadNca(GameFile);
|
||||||
|
break;
|
||||||
|
case ".nsp":
|
||||||
|
Console.WriteLine("Loading as NSP.");
|
||||||
|
Device.LoadNsp(GameFile);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Console.WriteLine("Loading as homebrew.");
|
||||||
|
Device.LoadProgram(GameFile);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
StartRenderer();
|
||||||
|
|
||||||
|
IsLoaded = true;
|
||||||
|
|
||||||
|
this.ActivateSignal("success");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadGameFolder(string ExeFsPath)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(ExeFsPath))
|
||||||
|
{
|
||||||
|
this.ActivateSignal("failed", $"Directory {ExeFsPath} does not exist.");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShutdownEmulation();
|
||||||
|
|
||||||
|
InitializeEmulator();
|
||||||
|
|
||||||
|
string[] RomFsFiles = Directory.GetFiles(ExeFsPath, "*.istorage");
|
||||||
|
|
||||||
|
if (RomFsFiles.Length == 0)
|
||||||
|
{
|
||||||
|
RomFsFiles = Directory.GetFiles(ExeFsPath, "*.romfs");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RomFsFiles.Length > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Loading as cart with RomFS.");
|
||||||
|
|
||||||
|
Device.LoadCart(ExeFsPath, RomFsFiles[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("Loading as cart WITHOUT RomFS.");
|
||||||
|
|
||||||
|
Device.LoadCart(ExeFsPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
StartRenderer();
|
||||||
|
|
||||||
|
IsLoaded = true;
|
||||||
|
|
||||||
|
this.ActivateSignal("success");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShutdownEmulation()
|
||||||
|
{
|
||||||
|
if(IsClosing || !IsLoaded)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsClosing = true;
|
||||||
|
|
||||||
|
Renderer?.ClearActions();
|
||||||
|
|
||||||
|
RenderScreen?.Close();
|
||||||
|
|
||||||
|
RenderScreen?.Dispose();
|
||||||
|
|
||||||
|
Device?.Dispose();
|
||||||
|
|
||||||
|
AudioOut?.Dispose();
|
||||||
|
|
||||||
|
ConsoleLog.Stop();
|
||||||
|
|
||||||
|
while (RenderScreen!=null && RenderScreen.Exists)
|
||||||
|
{
|
||||||
|
Thread.Sleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderScreen = null;
|
||||||
|
Device = null;
|
||||||
|
AudioOut = null;
|
||||||
|
Renderer = null;
|
||||||
|
|
||||||
|
IsLoaded = false;
|
||||||
|
IsClosing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitializeEmulator()
|
||||||
|
{
|
||||||
|
Renderer = new OGLRenderer();
|
||||||
|
|
||||||
|
AudioOut = new OpenALAudioOut();
|
||||||
|
|
||||||
|
Device = new Switch(Renderer, AudioOut);
|
||||||
|
|
||||||
|
Config.Read(Device);
|
||||||
|
|
||||||
|
ConsoleLog.Start();
|
||||||
|
|
||||||
|
Device.Log.Updated += ConsoleLog.Log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartRenderer()
|
||||||
|
{
|
||||||
|
Thread RendererThread = new Thread(() =>
|
||||||
|
{
|
||||||
|
using (RenderScreen = new GLScreen(Device, Renderer))
|
||||||
|
{
|
||||||
|
RenderScreen.Closed += (o, e) => { ShutdownEmulation(); };
|
||||||
|
RenderScreen.MainLoop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
RendererThread.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
using Qml.Net;
|
using Qml.Net;
|
||||||
using System;
|
using Ryujinx.UI.Emulation;
|
||||||
|
|
||||||
|
using static Qml.Net.Qml;
|
||||||
|
|
||||||
namespace Ryujinx.UI
|
namespace Ryujinx.UI
|
||||||
{
|
{
|
||||||
|
@ -7,12 +9,14 @@ namespace Ryujinx.UI
|
||||||
{
|
{
|
||||||
static int Main(string[] args)
|
static int Main(string[] args)
|
||||||
{
|
{
|
||||||
QQuickStyle.SetStyle("Material");
|
QQuickStyle.SetStyle("Fusion");
|
||||||
|
|
||||||
using (var Application = new QGuiApplication(args))
|
using (var Application = new QGuiApplication(args))
|
||||||
{
|
{
|
||||||
using (var QmlEngine = new QQmlApplicationEngine())
|
using (var QmlEngine = new QQmlApplicationEngine())
|
||||||
{
|
{
|
||||||
|
RegisterType<EmulationController>("Ryujinx");
|
||||||
|
|
||||||
QmlEngine.Load("UI/MainWindow.qml");
|
QmlEngine.Load("UI/MainWindow.qml");
|
||||||
|
|
||||||
return Application.Exec();
|
return Application.Exec();
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="OpenTK.NetStandard" Version="1.0.4" />
|
||||||
<PackageReference Include="Qml.Net" Version="0.6.2" />
|
<PackageReference Include="Qml.Net" Version="0.6.2" />
|
||||||
<PackageReference Include="Qml.Net.LinuxBinaries" Version="0.6.2" />
|
<PackageReference Include="Qml.Net.LinuxBinaries" Version="0.6.2" />
|
||||||
<PackageReference Include="Qml.Net.OSXBinaries" Version="0.6.2" />
|
<PackageReference Include="Qml.Net.OSXBinaries" Version="0.6.2" />
|
||||||
|
|
1
Ryujinx.UI/UI/Images/closeGame.svg
Normal file
1
Ryujinx.UI/UI/Images/closeGame.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"><path d="M38 12.83L35.17 10 24 21.17 12.83 10 10 12.83 21.17 24 10 35.17 12.83 38 24 26.83 35.17 38 38 35.17 26.83 24z"/></svg>
|
After Width: | Height: | Size: 210 B |
|
@ -1,8 +1,10 @@
|
||||||
import QtQuick 2.9
|
import QtQuick 2.11
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
import QtQuick.Controls 2.3
|
import QtQuick.Controls 2.4
|
||||||
import QtQuick.Controls.Material 2.1
|
import QtQuick.Controls.Material 2.4
|
||||||
import QtQuick.Dialogs 1.0
|
import QtQuick.Dialogs 1.3
|
||||||
|
|
||||||
|
import Ryujinx 1.0
|
||||||
|
|
||||||
ApplicationWindow {
|
ApplicationWindow {
|
||||||
id: window
|
id: window
|
||||||
|
@ -11,9 +13,39 @@ ApplicationWindow {
|
||||||
visible: true
|
visible: true
|
||||||
title: "Ryujinx"
|
title: "Ryujinx"
|
||||||
|
|
||||||
Material.theme: Material.Light
|
menuBar: MenuBar {
|
||||||
Material.accent: '#41cd52'
|
Menu{
|
||||||
Material.primary: '#41cd52'
|
leftPadding: 5
|
||||||
|
leftMargin: 0
|
||||||
|
title: "&File"
|
||||||
|
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
id: loadGameMenuItem
|
||||||
|
text: "Load Game File"
|
||||||
|
onClicked: {
|
||||||
|
loadDialog.loadGame()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
id: loadGameFolderMenuItem
|
||||||
|
text: "Load Game Folder"
|
||||||
|
onClicked: {
|
||||||
|
loadDialog.loadGame()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuSeparator{}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Exit"
|
||||||
|
onClicked: {
|
||||||
|
Qt.quit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
header: ToolBar {
|
header: ToolBar {
|
||||||
id: toolBar
|
id: toolBar
|
||||||
|
@ -23,23 +55,6 @@ ApplicationWindow {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 20
|
spacing: 20
|
||||||
|
|
||||||
ToolButton {
|
|
||||||
id: drawerButton
|
|
||||||
text: qsTr("")
|
|
||||||
spacing: 3
|
|
||||||
display: AbstractButton.IconOnly
|
|
||||||
icon.source: !drawer.visible ? "./Images/drawer.png"
|
|
||||||
: "./Images/arrowBack.svg"
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
if (drawer.visible) {
|
|
||||||
drawer.close()
|
|
||||||
} else {
|
|
||||||
drawer.open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: mainControlPanel
|
id: mainControlPanel
|
||||||
spacing: 20
|
spacing: 20
|
||||||
|
@ -48,7 +63,8 @@ ApplicationWindow {
|
||||||
|
|
||||||
ToolButton {
|
ToolButton {
|
||||||
id: openGameFileButton
|
id: openGameFileButton
|
||||||
display: AbstractButton.IconOnly
|
text: qsTr("Load Game File")
|
||||||
|
display: AbstractButton.TextUnderIcon
|
||||||
icon.source: "./Images/loadGame.svg"
|
icon.source: "./Images/loadGame.svg"
|
||||||
ToolTip {
|
ToolTip {
|
||||||
text: qsTr("Load Game File")
|
text: qsTr("Load Game File")
|
||||||
|
@ -61,7 +77,8 @@ ApplicationWindow {
|
||||||
|
|
||||||
ToolButton {
|
ToolButton {
|
||||||
id: openGameFolderButton
|
id: openGameFolderButton
|
||||||
display: AbstractButton.IconOnly
|
text: qsTr("Load Game Folder")
|
||||||
|
display: AbstractButton.TextUnderIcon
|
||||||
icon.source: "./Images/loadFolder.svg"
|
icon.source: "./Images/loadFolder.svg"
|
||||||
ToolTip {
|
ToolTip {
|
||||||
text: qsTr("Load Game Folder")
|
text: qsTr("Load Game Folder")
|
||||||
|
@ -71,6 +88,24 @@ ApplicationWindow {
|
||||||
loadDialog.loadGameFolder()
|
loadDialog.loadGameFolder()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToolSeparator{}
|
||||||
|
|
||||||
|
ToolButton {
|
||||||
|
id: closeGameButton
|
||||||
|
text: qsTr("Stop")
|
||||||
|
display: AbstractButton.TextUnderIcon
|
||||||
|
icon.source: "./Images/closeGame.svg"
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
ToolTip {
|
||||||
|
text: qsTr("Close Current Game")
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
controller.shutdownEmulation()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,77 +115,6 @@ ApplicationWindow {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
Drawer {
|
|
||||||
id: drawer
|
|
||||||
width: window.width / 3
|
|
||||||
height: window.height
|
|
||||||
topMargin: toolBar.height
|
|
||||||
spacing: 10
|
|
||||||
|
|
||||||
Rectangle{
|
|
||||||
|
|
||||||
Column{
|
|
||||||
id: column
|
|
||||||
x: 40
|
|
||||||
y: 20
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: 40
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 20
|
|
||||||
spacing: 20
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: logo
|
|
||||||
width: 100
|
|
||||||
height: 100
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
source: "./Images/ryujinxLogo.png"
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: appLabel
|
|
||||||
text: qsTr("Ryujinx")
|
|
||||||
font.bold: true
|
|
||||||
font.pointSize: 16
|
|
||||||
font.weight: Font.Bold
|
|
||||||
lineHeight: 1.2
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle{
|
|
||||||
id: rectangle
|
|
||||||
anchors.top: appLabel.bottom
|
|
||||||
anchors.topMargin: 20
|
|
||||||
|
|
||||||
ListView {
|
|
||||||
id: drawerMenuList
|
|
||||||
width: 100
|
|
||||||
height: 120
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 0
|
|
||||||
currentIndex: -1
|
|
||||||
|
|
||||||
delegate: ItemDelegate {
|
|
||||||
width: parent.width
|
|
||||||
text: model.title
|
|
||||||
highlighted: ListView.isCurrentItem
|
|
||||||
}
|
|
||||||
|
|
||||||
model: ListModel {
|
|
||||||
ListElement { title: "Games"}
|
|
||||||
ListElement { title: "Settings"}
|
|
||||||
ListElement { title: "Exit"}
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollIndicator.vertical: ScrollIndicator { }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FileDialog {
|
FileDialog {
|
||||||
id: loadDialog
|
id: loadDialog
|
||||||
selectMultiple: false
|
selectMultiple: false
|
||||||
|
@ -160,6 +124,17 @@ ApplicationWindow {
|
||||||
"All Supported Formats (*.xci *.nca *.nsp *.nso *.nro)"]
|
"All Supported Formats (*.xci *.nca *.nsp *.nso *.nro)"]
|
||||||
folder: shortcuts.home
|
folder: shortcuts.home
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
if(selectFolder )
|
||||||
|
{
|
||||||
|
controller.loadGameFolder(fileUrl)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
controller.loadGameFile(fileUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function loadGame() {
|
function loadGame() {
|
||||||
selectFolder = false
|
selectFolder = false
|
||||||
title = qsTr("Load Game File")
|
title = qsTr("Load Game File")
|
||||||
|
@ -174,9 +149,47 @@ ApplicationWindow {
|
||||||
open()
|
open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
EmulationController {
|
||||||
|
id: controller
|
||||||
|
|
||||||
|
onFailed: function(result) {
|
||||||
|
// alertBox.title = "Failed to load game"
|
||||||
|
// alertBox.text = result
|
||||||
|
|
||||||
|
// alertBox.open()
|
||||||
|
|
||||||
|
loadGameMenuItem.enabled = true
|
||||||
|
loadGameFolderMenuItem.enabled = true
|
||||||
|
openGameFileButton.enabled = true
|
||||||
|
openGameFolderButton.enabled = true
|
||||||
|
closeGameButton.enabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/*##^## Designer {
|
onSuccess: {
|
||||||
D{i:272;anchors_height:120;anchors_width:100}
|
loadGameMenuItem.enabled = false
|
||||||
|
loadGameFolderMenuItem.enabled = false
|
||||||
|
openGameFileButton.enabled = false
|
||||||
|
openGameFolderButton.enabled = false
|
||||||
|
closeGameButton.enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoaded: {
|
||||||
|
loadGameMenuItem.enabled = false
|
||||||
|
loadGameFolderMenuItem.enabled = false
|
||||||
|
openGameFileButton.enabled = false
|
||||||
|
openGameFolderButton.enabled = false
|
||||||
|
closeGameButton.enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnloaded: {
|
||||||
|
loadGameMenuItem.enabled = true
|
||||||
|
loadGameFolderMenuItem.enabled = true
|
||||||
|
openGameFileButton.enabled = true
|
||||||
|
openGameFolderButton.enabled = true
|
||||||
|
closeGameButton.enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
##^##*/
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx
|
namespace Ryujinx
|
||||||
{
|
{
|
||||||
static class ConsoleLog
|
public static class ConsoleLog
|
||||||
{
|
{
|
||||||
private static Thread MessageThread;
|
private static Thread MessageThread;
|
||||||
|
|
||||||
|
@ -26,31 +26,7 @@ namespace Ryujinx
|
||||||
{ LogLevel.Error, ConsoleColor.Red }
|
{ LogLevel.Error, ConsoleColor.Red }
|
||||||
};
|
};
|
||||||
|
|
||||||
MessageQueue = new BlockingCollection<LogEventArgs>();
|
Start();
|
||||||
|
|
||||||
ConsoleLock = new object();
|
|
||||||
|
|
||||||
MessageThread = new Thread(() =>
|
|
||||||
{
|
|
||||||
while (!MessageQueue.IsCompleted)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PrintLog(MessageQueue.Take());
|
|
||||||
}
|
|
||||||
catch (InvalidOperationException)
|
|
||||||
{
|
|
||||||
// IOE means that Take() was called on a completed collection.
|
|
||||||
// Some other thread can call CompleteAdding after we pass the
|
|
||||||
// IsCompleted check but before we call Take.
|
|
||||||
// We can simply catch the exception since the loop will break
|
|
||||||
// on the next iteration.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
MessageThread.IsBackground = true;
|
|
||||||
MessageThread.Start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PrintLog(LogEventArgs e)
|
private static void PrintLog(LogEventArgs e)
|
||||||
|
@ -84,5 +60,44 @@ namespace Ryujinx
|
||||||
MessageQueue.Add(e);
|
MessageQueue.Add(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Stop()
|
||||||
|
{
|
||||||
|
MessageQueue?.CompleteAdding();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Start()
|
||||||
|
{
|
||||||
|
if (MessageQueue != null && !MessageQueue.IsCompleted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageQueue = new BlockingCollection<LogEventArgs>();
|
||||||
|
|
||||||
|
ConsoleLock = new object();
|
||||||
|
|
||||||
|
MessageThread = new Thread(() =>
|
||||||
|
{
|
||||||
|
while (!MessageQueue.IsCompleted)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PrintLog(MessageQueue.Take());
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
// IOE means that Take() was called on a completed collection.
|
||||||
|
// Some other thread can call CompleteAdding after we pass the
|
||||||
|
// IsCompleted check but before we call Take.
|
||||||
|
// We can simply catch the exception since the loop will break
|
||||||
|
// on the next iteration.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
MessageThread.IsBackground = true;
|
||||||
|
MessageThread.Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -60,7 +60,7 @@ namespace Ryujinx
|
||||||
|
|
||||||
long Ticks = 0;
|
long Ticks = 0;
|
||||||
|
|
||||||
while (Exists && !IsExiting)
|
while (!IsDisposed && Exists && !IsExiting)
|
||||||
{
|
{
|
||||||
if (Device.WaitFifo())
|
if (Device.WaitFifo())
|
||||||
{
|
{
|
||||||
|
@ -109,7 +109,7 @@ namespace Ryujinx
|
||||||
{
|
{
|
||||||
ProcessEvents();
|
ProcessEvents();
|
||||||
|
|
||||||
if (!IsExiting)
|
if (!IsDisposed && !IsExiting)
|
||||||
{
|
{
|
||||||
UpdateFrame();
|
UpdateFrame();
|
||||||
|
|
||||||
|
@ -266,11 +266,18 @@ namespace Ryujinx
|
||||||
|
|
||||||
TitleEvent = true;
|
TitleEvent = true;
|
||||||
|
|
||||||
|
if (!IsDisposed && Exists)
|
||||||
|
{
|
||||||
SwapBuffers();
|
SwapBuffers();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Device.System.SignalVsync();
|
Device.System.SignalVsync();
|
||||||
|
|
||||||
Device.VsyncEvent.Set();
|
Device.VsyncEvent?.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnUnload(EventArgs e)
|
protected override void OnUnload(EventArgs e)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue