From 313f8d2eb6e4833170d685d6afd940c077e066f6 Mon Sep 17 00:00:00 2001 From: Ac_K Date: Sun, 15 Nov 2020 22:30:20 +0100 Subject: [PATCH] am/lbl/hid/pctl: Enabled VR Rendering (#1688) * am/lbl/hid/pctl: Enabled VR Rendering This PR enable VR rendering on games which support it through the Toy-Con VR Goggles. Please remember Ryujinx currently don't support console SixAxis sensor and for now, in some games, the view can't be moved. Everything is implemented accordingly to RE: - am: ICommonStateGetter: SetVrModeEnabled, BeginVrModeEx, EndVrModeEx. - lbl: ILblController: SetBrightnessReflectionDelayLevel, GetBrightnessReflectionDelayLevel, SetCurrentAmbientLightSensorMapping, GetCurrentAmbientLightSensorMapping, SetCurrentBrightnessSettingForVrMode, GetCurrentBrightnessSettingForVrMode, EnableVrMode, DisableVrMode, IsVrModeEnabled. - pctl: IParentalControlService: ConfirmStereoVisionPermission, ConfirmStereoVisionRestrictionConfigurable, GetStereoVisionRestriction, SetStereoVisionRestriction, ResetConfirmedStereoVisionPermission, IsStereoVisionPermitted. - hid: IHidServer: ResetSevenSixAxisSensorTimestamp is stubbed because we don't support console SixAxisSensor for now. Maybe we could add a setting later to enable or disable VR. But I think it's fine to keep this always available since you have to enable it in games. * Fix permission flag check * Address gdkchan feedback --- .../SystemAppletProxy/ICommonStateGetter.cs | 68 ++++++++-- Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs | 11 ++ .../HOS/Services/Lbl/ILblController.cs | 88 ++++++++++++- .../HOS/Services/Lbl/LblControllerServer.cs | 54 ++++++++ .../IParentalControlService.cs | 121 ++++++++++++++++++ Ryujinx.HLE/HOS/Services/Pctl/ResultCode.cs | 8 +- 6 files changed, 337 insertions(+), 13 deletions(-) create mode 100644 Ryujinx.HLE/HOS/Services/Lbl/LblControllerServer.cs diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs index 82e18922..16b78734 100644 --- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs @@ -8,15 +8,17 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys { class ICommonStateGetter : IpcService { - private Apm.ManagerServer apmManagerServer; - private Apm.SystemManagerServer apmSystemManagerServer; + private Apm.ManagerServer _apmManagerServer; + private Apm.SystemManagerServer _apmSystemManagerServer; + private Lbl.LblControllerServer _lblControllerServer; - private bool _vrModeEnabled = false; + private bool _vrModeEnabled = true; public ICommonStateGetter(ServiceCtx context) { - apmManagerServer = new Apm.ManagerServer(context); - apmSystemManagerServer = new Apm.SystemManagerServer(context); + _apmManagerServer = new Apm.ManagerServer(context); + _apmSystemManagerServer = new Apm.SystemManagerServer(context); + _lblControllerServer = new Lbl.LblControllerServer(context); } [Command(0)] @@ -66,7 +68,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys // GetPerformanceMode() -> nn::apm::PerformanceMode public ResultCode GetPerformanceMode(ServiceCtx context) { - return (ResultCode)apmManagerServer.GetPerformanceMode(context); + return (ResultCode)_apmManagerServer.GetPerformanceMode(context); } [Command(8)] @@ -98,6 +100,56 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys return ResultCode.Success; } + [Command(51)] // 3.0.0+ + // SetVrModeEnabled(b8) + public ResultCode SetVrModeEnabled(ServiceCtx context) + { + bool vrModeEnabled = context.RequestData.ReadBoolean(); + + UpdateVrMode(vrModeEnabled); + + return ResultCode.Success; + } + + [Command(53)] // 7.0.0+ + // BeginVrModeEx() + public ResultCode BeginVrModeEx(ServiceCtx context) + { + UpdateVrMode(true); + + return ResultCode.Success; + } + + [Command(54)] // 7.0.0+ + // EndVrModeEx() + public ResultCode EndVrModeEx(ServiceCtx context) + { + UpdateVrMode(false); + + return ResultCode.Success; + } + + private void UpdateVrMode(bool vrModeEnabled) + { + if (_vrModeEnabled == vrModeEnabled) + { + return; + } + + _vrModeEnabled = vrModeEnabled; + + if (vrModeEnabled) + { + _lblControllerServer.EnableVrMode(); + } + else + { + _lblControllerServer.DisableVrMode(); + } + + // TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used. + } + [Command(60)] // 3.0.0+ // GetDefaultDisplayResolution() -> (u32, u32) public ResultCode GetDefaultDisplayResolution(ServiceCtx context) @@ -135,7 +187,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys return ResultCode.InvalidParameters; } - apmSystemManagerServer.SetCpuBoostMode((Apm.CpuBoostMode)cpuBoostMode); + _apmSystemManagerServer.SetCpuBoostMode((Apm.CpuBoostMode)cpuBoostMode); // TODO: It signals an internal event of ICommonStateGetter. We have to determine where this event is used. @@ -146,7 +198,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys // GetCurrentPerformanceConfiguration() -> nn::apm::PerformanceConfiguration public ResultCode GetCurrentPerformanceConfiguration(ServiceCtx context) { - return (ResultCode)apmSystemManagerServer.GetCurrentPerformanceConfiguration(context); + return (ResultCode)_apmSystemManagerServer.GetCurrentPerformanceConfiguration(context); } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs index 4001cfdd..d3bf9319 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs @@ -1190,6 +1190,17 @@ namespace Ryujinx.HLE.HOS.Services.Hid return ResultCode.Success; } + [Command(310)] // 6.0.0+ + // ResetSevenSixAxisSensorTimestamp(pid, nn::applet::AppletResourceUserId) + public ResultCode ResetSevenSixAxisSensorTimestamp(ServiceCtx context) + { + long appletResourceUserId = context.RequestData.ReadInt64(); + + Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId }); + + return ResultCode.Success; + } + [Command(400)] // IsUsbFullKeyControllerEnabled() -> bool IsEnabled public ResultCode IsUsbFullKeyControllerEnabled(ServiceCtx context) diff --git a/Ryujinx.HLE/HOS/Services/Lbl/ILblController.cs b/Ryujinx.HLE/HOS/Services/Lbl/ILblController.cs index de84095e..6964de6b 100644 --- a/Ryujinx.HLE/HOS/Services/Lbl/ILblController.cs +++ b/Ryujinx.HLE/HOS/Services/Lbl/ILblController.cs @@ -1,8 +1,92 @@ namespace Ryujinx.HLE.HOS.Services.Lbl { - [Service("lbl")] - class ILblController : IpcService + abstract class ILblController : IpcService { public ILblController(ServiceCtx context) { } + + protected abstract void SetCurrentBrightnessSettingForVrMode(float currentBrightnessSettingForVrMode); + protected abstract float GetCurrentBrightnessSettingForVrMode(); + internal abstract void EnableVrMode(); + internal abstract void DisableVrMode(); + protected abstract bool IsVrModeEnabled(); + + [Command(17)] + // SetBrightnessReflectionDelayLevel(float, float) + public ResultCode SetBrightnessReflectionDelayLevel(ServiceCtx context) + { + return ResultCode.Success; + } + + [Command(18)] + // GetBrightnessReflectionDelayLevel(float) -> float + public ResultCode GetBrightnessReflectionDelayLevel(ServiceCtx context) + { + context.ResponseData.Write(0.0f); + + return ResultCode.Success; + } + + [Command(21)] + // SetCurrentAmbientLightSensorMapping(unknown<0xC>) + public ResultCode SetCurrentAmbientLightSensorMapping(ServiceCtx context) + { + return ResultCode.Success; + } + + [Command(22)] + // GetCurrentAmbientLightSensorMapping() -> unknown<0xC> + public ResultCode GetCurrentAmbientLightSensorMapping(ServiceCtx context) + { + return ResultCode.Success; + } + + [Command(24)] // 3.0.0+ + // SetCurrentBrightnessSettingForVrMode(float) + public ResultCode SetCurrentBrightnessSettingForVrMode(ServiceCtx context) + { + float currentBrightnessSettingForVrMode = context.RequestData.ReadSingle(); + + SetCurrentBrightnessSettingForVrMode(currentBrightnessSettingForVrMode); + + return ResultCode.Success; + } + + [Command(25)] // 3.0.0+ + // GetCurrentBrightnessSettingForVrMode() -> float + public ResultCode GetCurrentBrightnessSettingForVrMode(ServiceCtx context) + { + float currentBrightnessSettingForVrMode = GetCurrentBrightnessSettingForVrMode(); + + context.ResponseData.Write(currentBrightnessSettingForVrMode); + + return ResultCode.Success; + } + + [Command(26)] // 3.0.0+ + // EnableVrMode() + public ResultCode EnableVrMode(ServiceCtx context) + { + EnableVrMode(); + + return ResultCode.Success; + } + + [Command(27)] // 3.0.0+ + // DisableVrMode() + public ResultCode DisableVrMode(ServiceCtx context) + { + DisableVrMode(); + + return ResultCode.Success; + } + + [Command(28)] // 3.0.0+ + // IsVrModeEnabled() -> bool + public ResultCode IsVrModeEnabled(ServiceCtx context) + { + context.ResponseData.Write(IsVrModeEnabled()); + + return ResultCode.Success; + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Lbl/LblControllerServer.cs b/Ryujinx.HLE/HOS/Services/Lbl/LblControllerServer.cs new file mode 100644 index 00000000..b68be1f2 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Lbl/LblControllerServer.cs @@ -0,0 +1,54 @@ +namespace Ryujinx.HLE.HOS.Services.Lbl +{ + [Service("lbl")] + class LblControllerServer : ILblController + { + private bool _vrModeEnabled; + private float _currentBrightnessSettingForVrMode; + + public LblControllerServer(ServiceCtx context) : base(context) { } + + protected override void SetCurrentBrightnessSettingForVrMode(float currentBrightnessSettingForVrMode) + { + if (float.IsNaN(currentBrightnessSettingForVrMode) || float.IsInfinity(currentBrightnessSettingForVrMode)) + { + _currentBrightnessSettingForVrMode = 0.0f; + + return; + } + + _currentBrightnessSettingForVrMode = currentBrightnessSettingForVrMode; + } + + protected override float GetCurrentBrightnessSettingForVrMode() + { + if (float.IsNaN(_currentBrightnessSettingForVrMode) || float.IsInfinity(_currentBrightnessSettingForVrMode)) + { + return 0.0f; + } + + return _currentBrightnessSettingForVrMode; + } + + internal override void EnableVrMode() + { + _vrModeEnabled = true; + + // NOTE: Service check _vrModeEnabled field value in a thread and then change the screen brightness. + // Since we don't support that. It's fine to do nothing. + } + + internal override void DisableVrMode() + { + _vrModeEnabled = false; + + // NOTE: Service check _vrModeEnabled field value in a thread and then change the screen brightness. + // Since we don't support that. It's fine to do nothing. + } + + protected override bool IsVrModeEnabled() + { + return _vrModeEnabled; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs b/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs index af468fca..0c792efa 100644 --- a/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs +++ b/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs @@ -10,6 +10,9 @@ namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory private ulong _titleId; private bool _freeCommunicationEnabled; private int[] _ratingAge; + private bool _featuresRestriction = false; + private bool _stereoVisionRestrictionConfigurable = true; + private bool _stereoVisionRestriction = false; public IParentalControlService(ServiceCtx context, bool withInitialize, int permissionFlag) { @@ -79,5 +82,123 @@ namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory return ResultCode.Success; } + + [Command(1013)] // 4.0.0+ + // ConfirmStereoVisionPermission() + public ResultCode ConfirmStereoVisionPermission(ServiceCtx context) + { + return IsStereoVisionPermittedImpl(); + } + + [Command(1061)] // 4.0.0+ + // ConfirmStereoVisionRestrictionConfigurable() + public ResultCode ConfirmStereoVisionRestrictionConfigurable(ServiceCtx context) + { + if ((_permissionFlag & 2) == 0) + { + return ResultCode.PermissionDenied; + } + + if (_stereoVisionRestrictionConfigurable) + { + return ResultCode.Success; + } + else + { + return ResultCode.StereoVisionRestrictionConfigurableDisabled; + } + } + + [Command(1062)] // 4.0.0+ + // GetStereoVisionRestriction() -> bool + public ResultCode GetStereoVisionRestriction(ServiceCtx context) + { + if ((_permissionFlag & 0x200) == 0) + { + return ResultCode.PermissionDenied; + } + + bool stereoVisionRestriction = false; + + if (_stereoVisionRestrictionConfigurable) + { + stereoVisionRestriction = _stereoVisionRestriction; + } + + context.ResponseData.Write(stereoVisionRestriction); + + return ResultCode.Success; + } + + [Command(1063)] // 4.0.0+ + // SetStereoVisionRestriction(bool) + public ResultCode SetStereoVisionRestriction(ServiceCtx context) + { + if ((_permissionFlag & 0x200) == 0) + { + return ResultCode.PermissionDenied; + } + + bool stereoVisionRestriction = context.RequestData.ReadBoolean(); + + if (!_featuresRestriction) + { + if (_stereoVisionRestrictionConfigurable) + { + _stereoVisionRestriction = stereoVisionRestriction; + + // TODO: It signals an internal event of service. We have to determine where this event is used. + } + } + + return ResultCode.Success; + } + + [Command(1064)] // 5.0.0+ + // ResetConfirmedStereoVisionPermission() + public ResultCode ResetConfirmedStereoVisionPermission(ServiceCtx context) + { + return ResultCode.Success; + } + + [Command(1065)] // 5.0.0+ + // IsStereoVisionPermitted() -> bool + public ResultCode IsStereoVisionPermitted(ServiceCtx context) + { + bool isStereoVisionPermitted = false; + + ResultCode resultCode = IsStereoVisionPermittedImpl(); + + if (resultCode == ResultCode.Success) + { + isStereoVisionPermitted = true; + } + + context.ResponseData.Write(isStereoVisionPermitted); + + return resultCode; + } + + private ResultCode IsStereoVisionPermittedImpl() + { + /* + // TODO: Application Exemptions are readed from file "appExemptions.dat" in the service savedata. + // Since we don't support the pctl savedata for now, this can be implemented later. + + if (appExemption) + { + return ResultCode.Success; + } + */ + + if (_stereoVisionRestrictionConfigurable && _stereoVisionRestriction) + { + return ResultCode.StereoVisionDenied; + } + else + { + return ResultCode.Success; + } + } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Pctl/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Pctl/ResultCode.cs index bf58628c..fcf06ee9 100644 --- a/Ryujinx.HLE/HOS/Services/Pctl/ResultCode.cs +++ b/Ryujinx.HLE/HOS/Services/Pctl/ResultCode.cs @@ -7,8 +7,10 @@ Success = 0, - FreeCommunicationDisabled = (101 << ErrorCodeShift) | ModuleId, - InvalidPid = (131 << ErrorCodeShift) | ModuleId, - PermissionDenied = (133 << ErrorCodeShift) | ModuleId + FreeCommunicationDisabled = (101 << ErrorCodeShift) | ModuleId, + StereoVisionDenied = (104 << ErrorCodeShift) | ModuleId, + InvalidPid = (131 << ErrorCodeShift) | ModuleId, + PermissionDenied = (133 << ErrorCodeShift) | ModuleId, + StereoVisionRestrictionConfigurableDisabled = (181 << ErrorCodeShift) | ModuleId, } }