diff options
| author | Ac_K <Acoustik666@gmail.com> | 2021-09-19 12:57:39 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-09-19 12:57:39 +0200 |
| commit | 40d1acd1982705224413bc882f6ae25d4bf8ee1a (patch) | |
| tree | 9894e6bb40253952caecd467beead655a378d6aa /Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs | |
| parent | e17eb7bfafdd95084baea8e9f3dc77ee3f755347 (diff) | |
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
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs')
| -rw-r--r-- | Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs | 219 |
1 files changed, 153 insertions, 66 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs index 5f161bee..3008bf2c 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> _displayInfo; + private readonly Dictionary<ulong, DisplayInfo> _openDisplayInfo; private int _vsyncEventHandle; - public IApplicationDisplayService() + public IApplicationDisplayService(ViServiceType serviceType) { - _displays = new IdDictionary(); + _serviceType = serviceType; + _displayInfo = new List<DisplayInfo>(); + _openDisplayInfo = new Dictionary<ulong, DisplayInfo>(); + + void AddDisplayInfo(string name, bool layerLimitEnabled, ulong layerLimitMax, ulong width, ulong height) + { + DisplayInfo displayInfo = new DisplayInfo() + { + Name = new Array40<byte>(), + LayerLimitEnabled = layerLimitEnabled, + Padding = new Array7<byte>(), + 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<nns::hosbinder::IHOSBinderDriver> 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<nn::visrv::sf::ISystemDisplayService> 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<nn::visrv::sf::IManagerDisplayService> 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<nns::hosbinder::IHOSBinderDriver> public ResultCode GetIndirectDisplayTransactionService(ServiceCtx context) { + if (_serviceType > ViServiceType.System) + { + return ResultCode.InvalidRange; + } + MakeObject(context, new HOSBinderDriverServer()); return ResultCode.Success; } [CommandHipc(1000)] - // ListDisplays() -> (u64, buffer<nn::vi::DisplayInfo, 6>) + // ListDisplays() -> (u64 count, buffer<nn::vi::DisplayInfo, 6>) 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<DisplayInfo>()), (ulong)(Unsafe.SizeOf<DisplayInfo>()), 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 = ""; + + 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 OpenDisplayImpl(context, name); + } + + [CommandHipc(1011)] + // OpenDefaultDisplay() -> u64 display_id + public ResultCode OpenDefaultDisplay(ServiceCtx context) + { + return OpenDisplayImpl(context, "Default"); + } - long displayId = _displays.Add(new Display(name)); + private ResultCode OpenDisplayImpl(ServiceCtx context, string name) + { + if (name == "") + { + return ResultCode.InvalidValue; + } - context.ResponseData.Write(displayId); + 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(); + + // NOTE: Returns ResultCode.InvalidArguments if width and height pointer are null, doesn't occur in our case. - context.ResponseData.Write(1280); - context.ResponseData.Write(720); + // 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<Display>((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<bytes, 0x46>) public ResultCode GetIndirectLayerImageMap(ServiceCtx context) @@ -312,7 +413,12 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService // GetDisplayVsyncEvent(u64) -> handle<copy> 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 |
