From 40d1acd1982705224413bc882f6ae25d4bf8ee1a Mon Sep 17 00:00:00 2001 From: Ac_K Date: Sun, 19 Sep 2021 12:57:39 +0200 Subject: [PATCH] vi: Unify resolutions values and accurate implementation of them. (#2640) * vi: Unify resolutions values and accurate implementation of them. To continue what was made in #2618, I've REd `vi` service a bit. Now values and checks related to displays are more accurate. - `am` GetDefaultDisplayResolution / GetDefaultDisplayResolutionChangeEvent have more informations on what the service does. - `vi:u/vi:m/vi:s` GetDisplayService are now accurate. - `IApplicationDisplay` GetRelayService, GetSystemDisplayService, GetManagerDisplayService, GetIndirectDisplayTransactionService, ListDisplays, OpenDisplay, OpenDefaultDisplay, CloseDisplay, GetDisplayResolution are now properly implemented. - Some other calls are cleaned or have extra checks accordingly to RE. Additionnaly, `IFriendService` have some wrong aligned things, and `pm:info` service placeholder was missing. * just use _openedDisplayInfo.Remove() * use context.Memory.Fill() * fix some casting * remove unneeded comment * cleanup * uses TryAdd * displayId > ulong * GetDisplayResolution > ulong * UL --- .../SystemAppletProxy/ICommonStateGetter.cs | 18 +- .../Friend/ServiceCreator/IFriendService.cs | 4 +- .../HOS/Services/Pm/IInformationInterface.cs | 8 + .../Services/Vi/IApplicationRootService.cs | 10 +- .../HOS/Services/Vi/IManagerRootService.cs | 10 +- .../HOS/Services/Vi/ISystemRootService.cs | 10 +- Ryujinx.HLE/HOS/Services/Vi/ResultCode.cs | 5 +- .../AndroidSurfaceComposerClient.cs | 19 ++ .../ApplicationDisplayService/Display.cs | 12 - .../IManagerDisplayService.cs | 14 ++ .../ISystemDisplayService.cs | 11 +- .../Types/DisplayInfo.cs | 16 ++ .../RootService/IApplicationDisplayService.cs | 219 ++++++++++++------ .../HOS/Services/Vi/Types/ViServiceType.cs | 9 + 14 files changed, 265 insertions(+), 100 deletions(-) create mode 100644 Ryujinx.HLE/HOS/Services/Pm/IInformationInterface.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/AndroidSurfaceComposerClient.cs delete mode 100644 Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Display.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Types/DisplayInfo.cs create mode 100644 Ryujinx.HLE/HOS/Services/Vi/Types/ViServiceType.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 a042b2e89..f420b4624 100644 --- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs +++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/SystemAppletProxy/ICommonStateGetter.cs @@ -3,6 +3,7 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.Settings.Types; +using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService; using Ryujinx.HLE.HOS.SystemState; using System; @@ -193,16 +194,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys // GetDefaultDisplayResolution() -> (u32, u32) public ResultCode GetDefaultDisplayResolution(ServiceCtx context) { - if (context.Device.System.State.DockedMode) - { - context.ResponseData.Write(1920); - context.ResponseData.Write(1080); - } - else - { - context.ResponseData.Write(1280); - context.ResponseData.Write(720); - } + // NOTE: Original service calls IOperationModeManager::GetDefaultDisplayResolution of omm service. + // IOperationModeManager::GetDefaultDisplayResolution of omm service call IManagerDisplayService::GetDisplayResolution of vi service. + (ulong width, ulong height) = AndroidSurfaceComposerClient.GetDisplayInfo(context); + + context.ResponseData.Write((uint)width); + context.ResponseData.Write((uint)height); return ResultCode.Success; } @@ -211,6 +208,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys // GetDefaultDisplayResolutionChangeEvent() -> handle public ResultCode GetDefaultDisplayResolutionChangeEvent(ServiceCtx context) { + // NOTE: Original service calls IOperationModeManager::GetDefaultDisplayResolutionChangeEvent of omm service. if (_displayResolutionChangedEventHandle == 0) { if (context.Process.HandleTable.GenerateHandle(context.Device.System.DisplayResolutionChangeEvent.ReadableEvent, out _displayResolutionChangedEventHandle) != KernelResult.Success) diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs index f8a7b3371..c3e1d967a 100644 --- a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs +++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs @@ -92,7 +92,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator // Padding context.RequestData.ReadInt32(); - UserId userId = context.RequestData.ReadStruct(); + UserId userId = context.RequestData.ReadStruct(); FriendFilter filter = context.RequestData.ReadStruct(); // Pid placeholder @@ -217,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize(0x40UL); - ulong bufferPosition = context.Request.RecvListBuff[0].Position; + ulong bufferPosition = context.Request.RecvListBuff[0].Position; if (userId.IsNull) { diff --git a/Ryujinx.HLE/HOS/Services/Pm/IInformationInterface.cs b/Ryujinx.HLE/HOS/Services/Pm/IInformationInterface.cs new file mode 100644 index 000000000..0be85c4f6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Pm/IInformationInterface.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.HLE.HOS.Services.Pm +{ + [Service("pm:info")] + class IInformationInterface : IpcService + { + public IInformationInterface(ServiceCtx context) { } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs b/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs index 7a2939635..9fddde577 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/IApplicationRootService.cs @@ -1,4 +1,5 @@ using Ryujinx.HLE.HOS.Services.Vi.RootService; +using Ryujinx.HLE.HOS.Services.Vi.Types; namespace Ryujinx.HLE.HOS.Services.Vi { @@ -11,9 +12,14 @@ namespace Ryujinx.HLE.HOS.Services.Vi // GetDisplayService(u32) -> object public ResultCode GetDisplayService(ServiceCtx context) { - int serviceType = context.RequestData.ReadInt32(); + ViServiceType serviceType = (ViServiceType)context.RequestData.ReadInt32(); - MakeObject(context, new IApplicationDisplayService()); + if (serviceType != ViServiceType.Application) + { + return ResultCode.InvalidRange; + } + + MakeObject(context, new IApplicationDisplayService(serviceType)); return ResultCode.Success; } diff --git a/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs b/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs index 28414ad66..6676b629c 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/IManagerRootService.cs @@ -1,4 +1,5 @@ using Ryujinx.HLE.HOS.Services.Vi.RootService; +using Ryujinx.HLE.HOS.Services.Vi.Types; namespace Ryujinx.HLE.HOS.Services.Vi { @@ -12,9 +13,14 @@ namespace Ryujinx.HLE.HOS.Services.Vi // GetDisplayService(u32) -> object public ResultCode GetDisplayService(ServiceCtx context) { - int serviceType = context.RequestData.ReadInt32(); + ViServiceType serviceType = (ViServiceType)context.RequestData.ReadInt32(); - MakeObject(context, new IApplicationDisplayService()); + if (serviceType != ViServiceType.Manager) + { + return ResultCode.InvalidRange; + } + + MakeObject(context, new IApplicationDisplayService(serviceType)); return ResultCode.Success; } diff --git a/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs b/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs index 1faf98c0f..b63f15c3b 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/ISystemRootService.cs @@ -1,4 +1,5 @@ using Ryujinx.HLE.HOS.Services.Vi.RootService; +using Ryujinx.HLE.HOS.Services.Vi.Types; namespace Ryujinx.HLE.HOS.Services.Vi { @@ -12,9 +13,14 @@ namespace Ryujinx.HLE.HOS.Services.Vi // GetDisplayService(u32) -> object public ResultCode GetDisplayService(ServiceCtx context) { - int serviceType = context.RequestData.ReadInt32(); + ViServiceType serviceType = (ViServiceType)context.RequestData.ReadInt32(); - MakeObject(context, new IApplicationDisplayService()); + if (serviceType != ViServiceType.System) + { + return ResultCode.InvalidRange; + } + + MakeObject(context, new IApplicationDisplayService(serviceType)); return ResultCode.Success; } diff --git a/Ryujinx.HLE/HOS/Services/Vi/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Vi/ResultCode.cs index 2c78c1a3d..d888e6445 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/ResultCode.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/ResultCode.cs @@ -9,6 +9,9 @@ namespace Ryujinx.HLE.HOS.Services.Vi InvalidArguments = (1 << ErrorCodeShift) | ModuleId, InvalidLayerSize = (4 << ErrorCodeShift) | ModuleId, - InvalidScalingMode = (6 << ErrorCodeShift) | ModuleId + InvalidRange = (5 << ErrorCodeShift) | ModuleId, + InvalidScalingMode = (6 << ErrorCodeShift) | ModuleId, + InvalidValue = (7 << ErrorCodeShift) | ModuleId, + AlreadyOpened = (9 << ErrorCodeShift) | ModuleId } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/AndroidSurfaceComposerClient.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/AndroidSurfaceComposerClient.cs new file mode 100644 index 000000000..1fa99e65a --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/AndroidSurfaceComposerClient.cs @@ -0,0 +1,19 @@ +namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService +{ + static class AndroidSurfaceComposerClient + { + // NOTE: This is android::SurfaceComposerClient::getDisplayInfo. + public static (ulong, ulong) GetDisplayInfo(ServiceCtx context, ulong displayId = 0) + { + // TODO: This need to be REd, it should returns the driver resolution and more. + if (context.Device.System.State.DockedMode) + { + return (1920, 1080); + } + else + { + return (1280, 720); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Display.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Display.cs deleted file mode 100644 index 47c7b2aea..000000000 --- a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Display.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Vi -{ - class Display - { - public string Name { get; private set; } - - public Display(string name) - { - Name = name; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs index 6cc103a04..fdab0f1b7 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/IManagerDisplayService.cs @@ -11,6 +11,20 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService _applicationDisplayService = applicationDisplayService; } + [CommandHipc(1102)] + // GetDisplayResolution(u64 display_id) -> (u64 width, u64 height) + public ResultCode GetDisplayResolution(ServiceCtx context) + { + ulong displayId = context.RequestData.ReadUInt64(); + + (ulong width, ulong height) = AndroidSurfaceComposerClient.GetDisplayInfo(context, displayId); + + context.ResponseData.Write(width); + context.ResponseData.Write(height); + + return ResultCode.Success; + } + [CommandHipc(2010)] // CreateManagedLayer(u32, u64, nn::applet::AppletResourceUserId) -> u64 public ResultCode CreateManagedLayer(ServiceCtx context) diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/ISystemDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/ISystemDisplayService.cs index e82099b19..82dd6af63 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/ISystemDisplayService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/ISystemDisplayService.cs @@ -42,12 +42,17 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService // GetDisplayMode(u64) -> nn::vi::DisplayModeInfo public ResultCode GetDisplayMode(ServiceCtx context) { - // TODO: De-hardcode resolution. - context.ResponseData.Write(1280); - context.ResponseData.Write(720); + ulong displayId = context.RequestData.ReadUInt64(); + + (ulong width, ulong height) = AndroidSurfaceComposerClient.GetDisplayInfo(context, displayId); + + context.ResponseData.Write((uint)width); + context.ResponseData.Write((uint)height); context.ResponseData.Write(60.0f); context.ResponseData.Write(0); + Logger.Stub?.PrintStub(LogClass.ServiceVi); + return ResultCode.Success; } } diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Types/DisplayInfo.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Types/DisplayInfo.cs new file mode 100644 index 000000000..06309da0b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/ApplicationDisplayService/Types/DisplayInfo.cs @@ -0,0 +1,16 @@ +using Ryujinx.Common.Memory; +using System.Runtime.InteropServices; + +namespace Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService.Types +{ + [StructLayout(LayoutKind.Sequential, Size = 0x60)] + struct DisplayInfo + { + public Array40 Name; + public bool LayerLimitEnabled; + public Array7 Padding; + public ulong LayerLimitMax; + public ulong Width; + public ulong Height; + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs index 5f161bee9..3008bf2c8 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs @@ -1,30 +1,69 @@ using Ryujinx.Common; using Ryujinx.Common.Logging; +using Ryujinx.Common.Memory; using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Services.SurfaceFlinger; using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService; +using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService.Types; +using Ryujinx.HLE.HOS.Services.Vi.Types; using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Text; namespace Ryujinx.HLE.HOS.Services.Vi.RootService { class IApplicationDisplayService : IpcService { - private readonly IdDictionary _displays; + private readonly ViServiceType _serviceType; + + private readonly List _displayInfo; + private readonly Dictionary _openDisplayInfo; private int _vsyncEventHandle; - public IApplicationDisplayService() + public IApplicationDisplayService(ViServiceType serviceType) { - _displays = new IdDictionary(); + _serviceType = serviceType; + _displayInfo = new List(); + _openDisplayInfo = new Dictionary(); + + void AddDisplayInfo(string name, bool layerLimitEnabled, ulong layerLimitMax, ulong width, ulong height) + { + DisplayInfo displayInfo = new DisplayInfo() + { + Name = new Array40(), + LayerLimitEnabled = layerLimitEnabled, + Padding = new Array7(), + LayerLimitMax = layerLimitMax, + Width = width, + Height = height + }; + + Encoding.ASCII.GetBytes(name).AsSpan().CopyTo(displayInfo.Name.ToSpan()); + + _displayInfo.Add(displayInfo); + } + + AddDisplayInfo("Default", true, 1, 1920, 1080); + AddDisplayInfo("External", true, 1, 1920, 1080); + AddDisplayInfo("Edid", true, 1, 0, 0); + AddDisplayInfo("Internal", true, 1, 1920, 1080); + AddDisplayInfo("Null", false, 0, 1920, 1080); } [CommandHipc(100)] // GetRelayService() -> object public ResultCode GetRelayService(ServiceCtx context) { + // FIXME: Should be _serviceType != ViServiceType.Application but guests crashes if we do this check. + if (_serviceType > ViServiceType.System) + { + return ResultCode.InvalidRange; + } + MakeObject(context, new HOSBinderDriverServer()); return ResultCode.Success; @@ -34,6 +73,12 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService // GetSystemDisplayService() -> object public ResultCode GetSystemDisplayService(ServiceCtx context) { + // FIXME: Should be _serviceType == ViServiceType.System but guests crashes if we do this check. + if (_serviceType > ViServiceType.System) + { + return ResultCode.InvalidRange; + } + MakeObject(context, new ISystemDisplayService(this)); return ResultCode.Success; @@ -43,6 +88,11 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService // GetManagerDisplayService() -> object public ResultCode GetManagerDisplayService(ServiceCtx context) { + if (_serviceType > ViServiceType.System) + { + return ResultCode.InvalidRange; + } + MakeObject(context, new IManagerDisplayService(this)); return ResultCode.Success; @@ -52,63 +102,120 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService // GetIndirectDisplayTransactionService() -> object public ResultCode GetIndirectDisplayTransactionService(ServiceCtx context) { + if (_serviceType > ViServiceType.System) + { + return ResultCode.InvalidRange; + } + MakeObject(context, new HOSBinderDriverServer()); return ResultCode.Success; } [CommandHipc(1000)] - // ListDisplays() -> (u64, buffer) + // ListDisplays() -> (u64 count, buffer) public ResultCode ListDisplays(ServiceCtx context) { - ulong recBuffPtr = context.Request.ReceiveBuff[0].Position; + ulong displayInfoBuffer = context.Request.ReceiveBuff[0].Position; - MemoryHelper.FillWithZeros(context.Memory, recBuffPtr, 0x60); + // TODO: Determine when more than one display is needed. + ulong displayCount = 1; - // Add only the default display to buffer - context.Memory.Write(recBuffPtr, Encoding.ASCII.GetBytes("Default")); - context.Memory.Write(recBuffPtr + 0x40, 0x1UL); - context.Memory.Write(recBuffPtr + 0x48, 0x1UL); - context.Memory.Write(recBuffPtr + 0x50, 1280UL); - context.Memory.Write(recBuffPtr + 0x58, 720UL); + for (int i = 0; i < (int)displayCount; i++) + { + context.Memory.Fill(displayInfoBuffer + (ulong)(i * Unsafe.SizeOf()), (ulong)(Unsafe.SizeOf()), 0x00); + context.Memory.Write(displayInfoBuffer, _displayInfo[i]); + } - context.ResponseData.Write(1L); + context.ResponseData.Write(displayCount); return ResultCode.Success; } [CommandHipc(1010)] - // OpenDisplay(nn::vi::DisplayName) -> u64 + // OpenDisplay(nn::vi::DisplayName) -> u64 display_id public ResultCode OpenDisplay(ServiceCtx context) { - string name = GetDisplayName(context); + string name = ""; - long displayId = _displays.Add(new Display(name)); + for (int index = 0; index < 8 && context.RequestData.BaseStream.Position < context.RequestData.BaseStream.Length; index++) + { + byte chr = context.RequestData.ReadByte(); - context.ResponseData.Write(displayId); + if (chr >= 0x20 && chr < 0x7f) + { + name += (char)chr; + } + } + + return OpenDisplayImpl(context, name); + } + + [CommandHipc(1011)] + // OpenDefaultDisplay() -> u64 display_id + public ResultCode OpenDefaultDisplay(ServiceCtx context) + { + return OpenDisplayImpl(context, "Default"); + } + + private ResultCode OpenDisplayImpl(ServiceCtx context, string name) + { + if (name == "") + { + return ResultCode.InvalidValue; + } + + int displayId = _displayInfo.FindIndex(display => Encoding.ASCII.GetString(display.Name.ToSpan()).Trim('\0') == name); + + if (displayId == -1) + { + return ResultCode.InvalidValue; + } + + if (!_openDisplayInfo.TryAdd((ulong)displayId, _displayInfo[displayId])) + { + return ResultCode.AlreadyOpened; + } + + context.ResponseData.Write((ulong)displayId); return ResultCode.Success; } [CommandHipc(1020)] - // CloseDisplay(u64) + // CloseDisplay(u64 display_id) public ResultCode CloseDisplay(ServiceCtx context) { - int displayId = context.RequestData.ReadInt32(); + ulong displayId = context.RequestData.ReadUInt64(); - _displays.Delete(displayId); + if (!_openDisplayInfo.Remove(displayId)) + { + return ResultCode.InvalidValue; + } return ResultCode.Success; } + [CommandHipc(1101)] + // SetDisplayEnabled(u32 enabled_bool, u64 display_id) + public ResultCode SetDisplayEnabled(ServiceCtx context) + { + // NOTE: Stubbed in original service. + return ResultCode.Success; + } + [CommandHipc(1102)] - // GetDisplayResolution(u64) -> (u64, u64) + // GetDisplayResolution(u64 display_id) -> (u64 width, u64 height) public ResultCode GetDisplayResolution(ServiceCtx context) { - long displayId = context.RequestData.ReadInt32(); + // NOTE: Not used in original service. + // ulong displayId = context.RequestData.ReadUInt64(); - context.ResponseData.Write(1280); - context.ResponseData.Write(720); + // NOTE: Returns ResultCode.InvalidArguments if width and height pointer are null, doesn't occur in our case. + + // NOTE: Values are hardcoded in original service. + context.ResponseData.Write(1280UL); // Width + context.ResponseData.Write(720UL); // Height return ResultCode.Success; } @@ -162,8 +269,6 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService ulong parcelPtr = context.Request.ReceiveBuff[0].Position; // TODO: support multi display. - Display disp = _displays.GetData((int)displayId); - IBinder producer = context.Device.System.SurfaceFlinger.CreateLayer(0, out long layerId); context.Device.System.SurfaceFlinger.SetRenderLayer(layerId); @@ -197,19 +302,30 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService // SetLayerScalingMode(u32, u64) public ResultCode SetLayerScalingMode(ServiceCtx context) { - int scalingMode = context.RequestData.ReadInt32(); - long layerId = context.RequestData.ReadInt64(); + /* + uint sourceScalingMode = context.RequestData.ReadUInt32(); + ulong layerId = context.RequestData.ReadUInt64(); + */ + // NOTE: Original service converts SourceScalingMode to DestinationScalingMode but does nothing with the converted value. return ResultCode.Success; } [CommandHipc(2102)] // 5.0.0+ - // ConvertScalingMode(unknown) -> unknown + // ConvertScalingMode(u32 source_scaling_mode) -> u64 destination_scaling_mode public ResultCode ConvertScalingMode(ServiceCtx context) { SourceScalingMode scalingMode = (SourceScalingMode)context.RequestData.ReadInt32(); - DestinationScalingMode? convertedScalingMode = ConvertScalingMode(scalingMode); + DestinationScalingMode? convertedScalingMode = scalingMode switch + { + SourceScalingMode.None => DestinationScalingMode.None, + SourceScalingMode.Freeze => DestinationScalingMode.Freeze, + SourceScalingMode.ScaleAndCrop => DestinationScalingMode.ScaleAndCrop, + SourceScalingMode.ScaleToWindow => DestinationScalingMode.ScaleToWindow, + SourceScalingMode.PreserveAspectRatio => DestinationScalingMode.PreserveAspectRatio, + _ => null, + }; if (!convertedScalingMode.HasValue) { @@ -217,8 +333,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService return ResultCode.InvalidArguments; } - if (scalingMode != SourceScalingMode.ScaleToWindow && - scalingMode != SourceScalingMode.PreserveAspectRatio) + if (scalingMode != SourceScalingMode.ScaleToWindow && scalingMode != SourceScalingMode.PreserveAspectRatio) { // Invalid scaling mode specified. return ResultCode.InvalidScalingMode; @@ -229,20 +344,6 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService return ResultCode.Success; } - private DestinationScalingMode? ConvertScalingMode(SourceScalingMode source) - { - switch (source) - { - case SourceScalingMode.None: return DestinationScalingMode.None; - case SourceScalingMode.Freeze: return DestinationScalingMode.Freeze; - case SourceScalingMode.ScaleAndCrop: return DestinationScalingMode.ScaleAndCrop; - case SourceScalingMode.ScaleToWindow: return DestinationScalingMode.ScaleToWindow; - case SourceScalingMode.PreserveAspectRatio: return DestinationScalingMode.PreserveAspectRatio; - } - - return null; - } - [CommandHipc(2450)] // GetIndirectLayerImageMap(s64 width, s64 height, u64 handle, nn::applet::AppletResourceUserId, pid) -> (s64, s64, buffer) public ResultCode GetIndirectLayerImageMap(ServiceCtx context) @@ -312,7 +413,12 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService // GetDisplayVsyncEvent(u64) -> handle public ResultCode GetDisplayVSyncEvent(ServiceCtx context) { - string name = GetDisplayName(context); + ulong displayId = context.RequestData.ReadUInt64(); + + if (!_openDisplayInfo.ContainsKey(displayId)) + { + return ResultCode.InvalidValue; + } if (_vsyncEventHandle == 0) { @@ -326,24 +432,5 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService return ResultCode.Success; } - - private string GetDisplayName(ServiceCtx context) - { - string name = string.Empty; - - for (int index = 0; index < 8 && - context.RequestData.BaseStream.Position < - context.RequestData.BaseStream.Length; index++) - { - byte chr = context.RequestData.ReadByte(); - - if (chr >= 0x20 && chr < 0x7f) - { - name += (char)chr; - } - } - - return name; - } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/Types/ViServiceType.cs b/Ryujinx.HLE/HOS/Services/Vi/Types/ViServiceType.cs new file mode 100644 index 000000000..ba6f8e5f8 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Vi/Types/ViServiceType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.HLE.HOS.Services.Vi.Types +{ + enum ViServiceType + { + Application, + Manager, + System + } +} \ No newline at end of file