RyuKen/Ryujinx.HLE/Switch.cs
Mary f556c80d02
Haydn: Part 1 (#2007)
* Haydn: Part 1

Based on my reverse of audio 11.0.0.

As always, core implementation under LGPLv3 for the same reasons as for Amadeus.

This place the bases of a more flexible audio system while making audout & audin accurate.

This have the following improvements:
- Complete reimplementation of audout and audin.
- Audin currently only have a dummy backend.
- Dramatically reduce CPU usage by up to 50% in common cases (SoundIO and OpenAL).
- Audio Renderer now can output to 5.1 devices when supported.
- Audio Renderer init its backend on demand instead of keeping two up all the time.
- All backends implementation are now in their own project.
- Ryujinx.Audio.Renderer was renamed Ryujinx.Audio and was refactored because of this.

As a note, games having issues with OpenAL haven't improved and will not
because of OpenAL design (stopping when buffers finish playing causing
possible audio "pops" when buffers are very small).

* Update for latest hexkyz's edits on Switchbrew

* audren: Rollback channel configuration changes

* Address gdkchan's comments

* Fix typo in OpenAL backend driver

* Address last comments

* Fix a nit

* Address gdkchan's comments
2021-02-26 01:11:56 +01:00

220 lines
6.7 KiB
C#

using LibHac.FsSystem;
using Ryujinx.Audio.Backends.CompatLayer;
using Ryujinx.Audio.Integration;
using Ryujinx.Common;
using Ryujinx.Configuration;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.Host1x;
using Ryujinx.Graphics.Nvdec;
using Ryujinx.Graphics.Vic;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services;
using Ryujinx.HLE.HOS.Services.Apm;
using Ryujinx.HLE.HOS.Services.Hid;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices;
using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.Memory;
using System;
namespace Ryujinx.HLE
{
public class Switch : IDisposable
{
public IHardwareDeviceDriver AudioDeviceDriver { get; private set; }
internal MemoryBlock Memory { get; private set; }
public GpuContext Gpu { get; private set; }
internal NvMemoryAllocator MemoryAllocator { get; private set; }
internal Host1xDevice Host1x { get; }
public VirtualFileSystem FileSystem { get; private set; }
public Horizon System { get; private set; }
public ApplicationLoader Application { get; }
public PerformanceStatistics Statistics { get; private set; }
public UserChannelPersistence UserChannelPersistence { get; }
public Hid Hid { get; private set; }
public IHostUiHandler UiHandler { get; set; }
public bool EnableDeviceVsync { get; set; } = true;
public Switch(VirtualFileSystem fileSystem, ContentManager contentManager, UserChannelPersistence userChannelPersistence, IRenderer renderer, IHardwareDeviceDriver audioDeviceDriver)
{
if (renderer == null)
{
throw new ArgumentNullException(nameof(renderer));
}
if (audioDeviceDriver == null)
{
throw new ArgumentNullException(nameof(audioDeviceDriver));
}
if (userChannelPersistence == null)
{
throw new ArgumentNullException(nameof(userChannelPersistence));
}
UserChannelPersistence = userChannelPersistence;
AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(audioDeviceDriver);
Memory = new MemoryBlock(1UL << 32);
Gpu = new GpuContext(renderer);
MemoryAllocator = new NvMemoryAllocator();
Host1x = new Host1xDevice(Gpu.Synchronization);
var nvdec = new NvdecDevice(Gpu.MemoryManager);
var vic = new VicDevice(Gpu.MemoryManager);
Host1x.RegisterDevice(ClassId.Nvdec, nvdec);
Host1x.RegisterDevice(ClassId.Vic, vic);
nvdec.FrameDecoded += (FrameDecodedEventArgs e) =>
{
// FIXME:
// Figure out what is causing frame ordering issues on H264.
// For now this is needed as workaround.
if (e.CodecId == CodecId.H264)
{
vic.SetSurfaceOverride(e.LumaOffset, e.ChromaOffset, 0);
}
else
{
vic.DisableSurfaceOverride();
}
};
FileSystem = fileSystem;
System = new Horizon(this, contentManager);
System.InitializeServices();
Statistics = new PerformanceStatistics();
Hid = new Hid(this, System.HidBaseAddress);
Hid.InitDevices();
Application = new ApplicationLoader(this, fileSystem, contentManager);
}
public void Initialize()
{
System.State.SetLanguage((SystemLanguage)ConfigurationState.Instance.System.Language.Value);
System.State.SetRegion((RegionCode)ConfigurationState.Instance.System.Region.Value);
EnableDeviceVsync = ConfigurationState.Instance.Graphics.EnableVsync;
System.State.DockedMode = ConfigurationState.Instance.System.EnableDockedMode;
System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default;
System.EnablePtc = ConfigurationState.Instance.System.EnablePtc;
System.FsIntegrityCheckLevel = GetIntegrityCheckLevel();
System.GlobalAccessLogMode = ConfigurationState.Instance.System.FsGlobalAccessLogMode;
ServiceConfiguration.IgnoreMissingServices = ConfigurationState.Instance.System.IgnoreMissingServices;
ConfigurationState.Instance.System.IgnoreMissingServices.Event += (object _, ReactiveEventArgs<bool> args) =>
{
ServiceConfiguration.IgnoreMissingServices = args.NewValue;
};
// Configure controllers
Hid.RefreshInputConfig(ConfigurationState.Instance.Hid.InputConfig.Value);
ConfigurationState.Instance.Hid.InputConfig.Event += Hid.RefreshInputConfigEvent;
}
public static IntegrityCheckLevel GetIntegrityCheckLevel()
{
return ConfigurationState.Instance.System.EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid
: IntegrityCheckLevel.None;
}
public void LoadCart(string exeFsDir, string romFsFile = null)
{
Application.LoadCart(exeFsDir, romFsFile);
}
public void LoadXci(string xciFile)
{
Application.LoadXci(xciFile);
}
public void LoadNca(string ncaFile)
{
Application.LoadNca(ncaFile);
}
public void LoadNsp(string nspFile)
{
Application.LoadNsp(nspFile);
}
public void LoadProgram(string fileName)
{
Application.LoadProgram(fileName);
}
public bool WaitFifo()
{
return Gpu.GPFifo.WaitForCommands();
}
public void ProcessFrame()
{
Gpu.Renderer.PreFrame();
Gpu.GPFifo.DispatchCalls();
}
public bool ConsumeFrameAvailable()
{
return Gpu.Window.ConsumeFrameAvailable();
}
public void PresentFrame(Action swapBuffersCallback)
{
Gpu.Window.Present(swapBuffersCallback);
}
public void DisposeGpu()
{
Gpu.Dispose();
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
ConfigurationState.Instance.Hid.InputConfig.Event -= Hid.RefreshInputConfigEvent;
System.Dispose();
Host1x.Dispose();
AudioDeviceDriver.Dispose();
FileSystem.Unload();
Memory.Dispose();
}
}
}
}