Просмотр исходного кода

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
Ac_K 5 лет назад
Родитель
Сommit
313f8d2eb6

+ 60 - 8
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);
         }
     }
 }

+ 11 - 0
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)

+ 86 - 2
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;
+        }
     }
 }

+ 54 - 0
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;
+        }
+    }
+}

+ 121 - 0
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;
+            }
+        }
     }
 }

+ 5 - 3
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,
     }
 }