From 380b95bc59e7dc419f89df951cdc086e792cb0ff Mon Sep 17 00:00:00 2001 From: Caian Benedicto Date: Tue, 12 Oct 2021 16:54:21 -0300 Subject: Inline software keyboard without input pop up dialog (#2180) * Initial implementation * Refactor dynamic text input keys out to facilitate configuration via UI * Fix code styling * Add per applet indirect layer handles * Remove static functions from SoftwareKeyboardRenderer * Remove inline keyboard reset delay * Remove inline keyboard V2 responses * Add inline keyboard soft-lock recovering * Add comments * Forward accept and cancel key names to the keyboard and add soft-lock prevention line * Add dummy window to handle paste events * Rework inline keyboard state machine and graphics * Implement IHostUiHandler interfaces on headless WindowBase class * Add inline keyboard assets * Fix coding style * Fix coding style * Change mode cycling shortcut to F6 * Fix invalid calc size error in games using extended calc * Remove unnecessary namespaces --- .../Vi/RootService/IApplicationDisplayService.cs | 62 ++++++++++++++++++---- 1 file changed, 51 insertions(+), 11 deletions(-) (limited to 'Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs') diff --git a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs index 9272fd80..267548dd 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs @@ -2,13 +2,16 @@ using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.Common.Memory; using Ryujinx.Cpu; +using Ryujinx.HLE.HOS.Applets; 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.Ui; using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService.Types; using Ryujinx.HLE.HOS.Services.Vi.Types; using System; +using System.Diagnostics; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; @@ -343,6 +346,20 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService return ResultCode.Success; } + private ulong GetA8B8G8R8LayerSize(int width, int height, out int pitch, out int alignment) + { + const int defaultAlignment = 0x1000; + const ulong defaultSize = 0x20000; + + alignment = defaultAlignment; + pitch = BitUtils.AlignUp(BitUtils.DivRoundUp(width * 32, 8), 64); + + int memorySize = pitch * BitUtils.AlignUp(height, 64); + ulong requiredMemorySize = (ulong)BitUtils.AlignUp(memorySize, alignment); + + return (requiredMemorySize + defaultSize - 1) / defaultSize * defaultSize; + } + [CommandHipc(2450)] // GetIndirectLayerImageMap(s64 width, s64 height, u64 handle, nn::applet::AppletResourceUserId, pid) -> (s64, s64, buffer) public ResultCode GetIndirectLayerImageMap(ServiceCtx context) @@ -350,13 +367,42 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService // The size of the layer buffer should be an aligned multiple of width * height // because it was created using GetIndirectLayerImageRequiredMemoryInfo as a guide. + long layerWidth = context.RequestData.ReadInt64(); + long layerHeight = context.RequestData.ReadInt64(); + long layerHandle = context.RequestData.ReadInt64(); ulong layerBuffPosition = context.Request.ReceiveBuff[0].Position; ulong layerBuffSize = context.Request.ReceiveBuff[0].Size; - // Fill the layer with zeros. - context.Memory.Fill(layerBuffPosition, layerBuffSize, 0x00); + // Get the pitch of the layer that is necessary to render correctly. + ulong size = GetA8B8G8R8LayerSize((int)layerWidth, (int)layerHeight, out int pitch, out _); + + Debug.Assert(layerBuffSize == size); + + RenderingSurfaceInfo surfaceInfo = new RenderingSurfaceInfo(ColorFormat.A8B8G8R8, (uint)layerWidth, (uint)layerHeight, (uint)pitch, (uint)layerBuffSize); + + // Get the applet associated with the handle. + object appletObject = context.Device.System.AppletState.IndirectLayerHandles.GetData((int)layerHandle); + + if (appletObject == null) + { + Logger.Error?.Print(LogClass.ServiceVi, $"Indirect layer handle {layerHandle} does not match any applet"); + + return ResultCode.Success; + } + + Debug.Assert(appletObject is IApplet); + + IApplet applet = appletObject as IApplet; - Logger.Stub?.PrintStub(LogClass.ServiceVi); + if (!applet.DrawTo(surfaceInfo, context.Memory, layerBuffPosition)) + { + Logger.Error?.Print(LogClass.ServiceVi, $"Applet did not draw on indirect layer handle {layerHandle}"); + + return ResultCode.Success; + } + + context.ResponseData.Write(layerWidth); + context.ResponseData.Write(layerHeight); return ResultCode.Success; } @@ -390,19 +436,13 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService } */ - const ulong defaultAlignment = 0x1000; - const ulong defaultSize = 0x20000; - // NOTE: The official service setup a A8B8G8R8 texture with a linear layout and then query its size. // As we don't need this texture on the emulator, we can just simplify this logic and directly // do a linear layout size calculation. (stride * height * bytePerPixel) - int pitch = BitUtils.AlignUp(BitUtils.DivRoundUp(width * 32, 8), 64); - int memorySize = pitch * BitUtils.AlignUp(height, 64); - ulong requiredMemorySize = (ulong)BitUtils.AlignUp(memorySize, (int)defaultAlignment); - ulong size = (requiredMemorySize + defaultSize - 1) / defaultSize * defaultSize; + ulong size = GetA8B8G8R8LayerSize(width, height, out int pitch, out int alignment); context.ResponseData.Write(size); - context.ResponseData.Write(defaultAlignment); + context.ResponseData.Write(alignment); } return ResultCode.Success; -- cgit v1.2.3