From c23dc434f8bcd7d8dede28ca81c6deb1c0f389ca Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 5 Aug 2018 02:07:20 -0300 Subject: [PATCH] Integrate shared font support --- ChocolArm64/Memory/AMemory.cs | 4 +- Ryujinx.HLE/Font/SharedFontManager.cs | 177 ------------------ Ryujinx.HLE/Hid/Hid.cs | 5 +- Ryujinx.HLE/Memory/DeviceMemory.cs | 15 ++ Ryujinx.HLE/OsHle/Font/SharedFontManager.cs | 126 +++++++++++++ .../{ => OsHle}/Font/SharedFontType.cs | 5 +- Ryujinx.HLE/OsHle/Handles/HSharedMem.cs | 44 ----- Ryujinx.HLE/OsHle/Horizon.cs | 5 + .../OsHle/Services/Pl/ISharedFontManager.cs | 84 +++++---- Ryujinx.HLE/Switch.cs | 3 - 10 files changed, 198 insertions(+), 270 deletions(-) delete mode 100644 Ryujinx.HLE/Font/SharedFontManager.cs create mode 100644 Ryujinx.HLE/OsHle/Font/SharedFontManager.cs rename Ryujinx.HLE/{ => OsHle}/Font/SharedFontType.cs (72%) delete mode 100644 Ryujinx.HLE/OsHle/Handles/HSharedMem.cs diff --git a/ChocolArm64/Memory/AMemory.cs b/ChocolArm64/Memory/AMemory.cs index a3a46b65db..341e6e3e38 100644 --- a/ChocolArm64/Memory/AMemory.cs +++ b/ChocolArm64/Memory/AMemory.cs @@ -141,7 +141,7 @@ namespace ChocolArm64.Memory return (byte*)Ptr + (Position & PageMask); } - return RamPtr; + throw new VmmPageFaultException(Position); } internal byte* TranslateWrite(long Position) @@ -181,7 +181,7 @@ namespace ChocolArm64.Memory return (byte*)Ptr + (Position & PageMask); } - return RamPtr; + throw new VmmPageFaultException(Position); } private void SetPTEntries(long VA, byte* Ptr, long Size) diff --git a/Ryujinx.HLE/Font/SharedFontManager.cs b/Ryujinx.HLE/Font/SharedFontManager.cs deleted file mode 100644 index fce270de86..0000000000 --- a/Ryujinx.HLE/Font/SharedFontManager.cs +++ /dev/null @@ -1,177 +0,0 @@ -using ChocolArm64.Exceptions; -using ChocolArm64.Memory; -using Ryujinx.HLE.Logging; -using Ryujinx.HLE.OsHle; -using Ryujinx.HLE.OsHle.Handles; -using Ryujinx.HLE.Resource; -using System; -using System.Collections.Generic; -using System.IO; - - -namespace Ryujinx.HLE.Font -{ - public class SharedFontManager - { - private const uint SharedMemorySize = 0x1100000; - private Logger Log; - - private string FontsPath; - - private object ShMemLock; - - private (AMemory, long, long)[] ShMemPositions; - - private Dictionary FontData; - - private uint[] LoadedFonts; - - public SharedFontManager(Logger Log, string SystemPath) - { - this.Log = Log; - this.FontsPath = Path.Combine(SystemPath, "fonts"); - - ShMemLock = new object(); - - ShMemPositions = new(AMemory, long, long)[0]; - - FontData = new Dictionary() - { - { SharedFontType.JapanUsEurope, GetData("FontStandard") }, - { SharedFontType.SimplifiedChinese, GetData("FontChineseSimplified") }, - { SharedFontType.SimplifiedChineseEx, GetData("FontExtendedChineseSimplified") }, - { SharedFontType.TraditionalChinese, GetData("FontChineseTraditional") }, - { SharedFontType.Korean, GetData("FontKorean") }, - { SharedFontType.NintendoEx, GetData("FontNintendoExtended") } - }; - - int FontMemoryUsage = 0; - foreach (byte[] data in FontData.Values) - { - FontMemoryUsage += data.Length; - FontMemoryUsage += 0x8; - } - - if (FontMemoryUsage > SharedMemorySize) - { - throw new InvalidSystemResourceException($"The sum of all fonts size exceed the shared memory size. Please make sure that the fonts don't exceed {SharedMemorySize} bytes in total. (actual size: {FontMemoryUsage} bytes)"); - } - - LoadedFonts = new uint[FontData.Count]; - } - - public byte[] GetData(string FontName) - { - string FontFilePath = Path.Combine(FontsPath, $"{FontName}.ttf"); - if (File.Exists(FontFilePath)) - { - return File.ReadAllBytes(FontFilePath); - } - else - { - throw new InvalidSystemResourceException($"Font \"{FontName}.ttf\" not found. Please provide it in \"{FontsPath}\"."); - } - } - - public void MapFont(SharedFontType FontType, AMemory Memory, long Position) - { - uint SharedMemoryAddressOffset = GetSharedMemoryAddressOffset(FontType); - // TODO: find what are the 8 bytes before the font - Memory.WriteUInt64(Position + SharedMemoryAddressOffset - 8, 0); - Memory.WriteBytes(Position + SharedMemoryAddressOffset, FontData[FontType]); - } - - public void PropagateNewMapFont(SharedFontType Type) - { - lock (ShMemLock) - { - foreach ((AMemory Memory, long Position, long Size) in ShMemPositions) - { - AMemoryMapInfo MemoryInfo = Memory.Manager.GetMapInfo(Position); - - if (MemoryInfo == null) - { - throw new VmmPageFaultException(Position); - } - - // The memory is read only, we need to changes that to add the new font - AMemoryPerm originalPerms = MemoryInfo.Perm; - Memory.Manager.Reprotect(Position, Size, AMemoryPerm.RW); - MapFont(Type, Memory, Position); - Memory.Manager.Reprotect(Position, Size, originalPerms); - } - } - } - - internal void ShMemMap(object sender, EventArgs e) - { - HSharedMem SharedMem = (HSharedMem)sender; - - lock (ShMemLock) - { - ShMemPositions = SharedMem.GetVirtualPositions(); - - (AMemory Memory, long Position, long Size) = ShMemPositions[ShMemPositions.Length - 1]; - - for (int Type = 0; Type < LoadedFonts.Length; Type++) - { - if (LoadedFonts[(int)Type] == 1) - { - MapFont((SharedFontType)Type, Memory, Position); - } - } - } - } - - internal void ShMemUnmap(object sender, EventArgs e) - { - HSharedMem SharedMem = (HSharedMem)sender; - - lock (ShMemLock) - { - ShMemPositions = SharedMem.GetVirtualPositions(); - } - } - - public void Load(SharedFontType FontType) - { - if (LoadedFonts[(int)FontType] == 0) - { - PropagateNewMapFont(FontType); - } - - LoadedFonts[(int)FontType] = 1; - } - - public uint GetLoadState(SharedFontType FontType) - { - if (LoadedFonts[(int)FontType] != 1) - { - // Some games don't request a load, so we need to load it here. - Load(FontType); - return 0; - } - return LoadedFonts[(int)FontType]; - } - - public uint GetFontSize(SharedFontType FontType) - { - return (uint)FontData[FontType].Length; - } - - public uint GetSharedMemoryAddressOffset(SharedFontType FontType) - { - uint Pos = 0x8; - - for (SharedFontType Type = SharedFontType.JapanUsEurope; Type < FontType; Type++) - { - Pos += GetFontSize(Type); - Pos += 0x8; - } - - return Pos; - } - - public int Count => FontData.Count; - } -} diff --git a/Ryujinx.HLE/Hid/Hid.cs b/Ryujinx.HLE/Hid/Hid.cs index 4f45df0ad8..492eb30a86 100644 --- a/Ryujinx.HLE/Hid/Hid.cs +++ b/Ryujinx.HLE/Hid/Hid.cs @@ -69,10 +69,7 @@ namespace Ryujinx.HLE.Input this.Device = Device; this.HidPosition = HidPosition; - for (long Offset = 0; Offset < Horizon.HidSize; Offset += 8) - { - Device.Memory.WriteInt64(HidPosition + Offset, 0); - } + Device.Memory.FillWithZeros(HidPosition, Horizon.HidSize); InitializeJoyconPair( JoyConColor.Body_Neon_Red, diff --git a/Ryujinx.HLE/Memory/DeviceMemory.cs b/Ryujinx.HLE/Memory/DeviceMemory.cs index e1de72f86f..3c5f2e5f78 100644 --- a/Ryujinx.HLE/Memory/DeviceMemory.cs +++ b/Ryujinx.HLE/Memory/DeviceMemory.cs @@ -102,6 +102,21 @@ namespace Ryujinx.HLE.Memory *((ulong*)(RamPtr + Position)) = Value; } + public void FillWithZeros(long Position, int Size) + { + int Size8 = Size & ~(8 - 1); + + for (int Offs = 0; Offs < Size8; Offs += 8) + { + WriteInt64(Position + Offs, 0); + } + + for (int Offs = Size8; Offs < (Size - Size8); Offs++) + { + WriteByte(Position + Offs, 0); + } + } + public void Dispose() { Dispose(true); diff --git a/Ryujinx.HLE/OsHle/Font/SharedFontManager.cs b/Ryujinx.HLE/OsHle/Font/SharedFontManager.cs new file mode 100644 index 0000000000..833c3d738a --- /dev/null +++ b/Ryujinx.HLE/OsHle/Font/SharedFontManager.cs @@ -0,0 +1,126 @@ +using Ryujinx.HLE.Memory; +using Ryujinx.HLE.OsHle.Utilities; +using Ryujinx.HLE.Resource; +using System.Collections.Generic; +using System.IO; + +namespace Ryujinx.HLE.OsHle.Font +{ + class SharedFontManager + { + private DeviceMemory Memory; + + private long PhysicalAddress; + + private string FontsPath; + + private struct FontInfo + { + public int Offset; + public int Size; + + public FontInfo(int Offset, int Size) + { + this.Offset = Offset; + this.Size = Size; + } + } + + private Dictionary FontData; + + private bool[] LoadedFonts; + + public SharedFontManager(Switch Device, long PhysicalAddress) + { + this.PhysicalAddress = PhysicalAddress; + + Memory = Device.Memory; + + FontsPath = Path.Combine(Device.VFs.GetSystemPath(), "fonts"); + + LoadedFonts = new bool[(int)SharedFontType.Count]; + } + + public void EnsureInitialized() + { + if (FontData == null) + { + Memory.FillWithZeros(PhysicalAddress, Horizon.FontSize); + + uint FontOffset = 0; + + FontInfo CreateFont(string Name) + { + string FontFilePath = Path.Combine(FontsPath, Name + ".ttf"); + + if (File.Exists(FontFilePath)) + { + byte[] Data = File.ReadAllBytes(FontFilePath); + + FontInfo Info = new FontInfo((int)FontOffset, Data.Length); + + WriteMagicAndSize(PhysicalAddress + FontOffset, Data.Length); + + FontOffset += 8; + + uint Start = FontOffset; + + for (; FontOffset - Start < Data.Length; FontOffset++) + { + Memory.WriteByte(PhysicalAddress + FontOffset, Data[FontOffset - Start]); + } + + return Info; + } + else + { + throw new InvalidSystemResourceException($"Font \"{Name}.ttf\" not found. Please provide it in \"{FontsPath}\"."); + } + } + + FontData = new Dictionary() + { + { SharedFontType.JapanUsEurope, CreateFont("FontStandard") }, + { SharedFontType.SimplifiedChinese, CreateFont("FontChineseSimplified") }, + { SharedFontType.SimplifiedChineseEx, CreateFont("FontExtendedChineseSimplified") }, + { SharedFontType.TraditionalChinese, CreateFont("FontChineseTraditional") }, + { SharedFontType.Korean, CreateFont("FontKorean") }, + { SharedFontType.NintendoEx, CreateFont("FontNintendoExtended") } + }; + + if (FontOffset > Horizon.FontSize) + { + throw new InvalidSystemResourceException( + $"The sum of all fonts size exceed the shared memory size. " + + $"Please make sure that the fonts don't exceed {Horizon.FontSize} bytes in total. " + + $"(actual size: {FontOffset} bytes)."); + } + } + } + + private void WriteMagicAndSize(long Position, int Size) + { + const int DecMagic = 0x18029a7f; + const int Key = 0x49621806; + + int EncryptedSize = EndianSwap.Swap32(Size ^ Key); + + Memory.WriteInt32(Position + 0, DecMagic); + Memory.WriteInt32(Position + 4, EncryptedSize); + } + + public int GetFontSize(SharedFontType FontType) + { + EnsureInitialized(); + + return FontData[FontType].Size; + } + + public int GetSharedMemoryAddressOffset(SharedFontType FontType) + { + EnsureInitialized(); + + return FontData[FontType].Offset + 8; + } + } +} diff --git a/Ryujinx.HLE/Font/SharedFontType.cs b/Ryujinx.HLE/OsHle/Font/SharedFontType.cs similarity index 72% rename from Ryujinx.HLE/Font/SharedFontType.cs rename to Ryujinx.HLE/OsHle/Font/SharedFontType.cs index ca8a42b0cd..80f42a7da6 100644 --- a/Ryujinx.HLE/Font/SharedFontType.cs +++ b/Ryujinx.HLE/OsHle/Font/SharedFontType.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Font +namespace Ryujinx.HLE.OsHle.Font { public enum SharedFontType { @@ -7,6 +7,7 @@ namespace Ryujinx.HLE.Font SimplifiedChineseEx = 2, TraditionalChinese = 3, Korean = 4, - NintendoEx = 5 + NintendoEx = 5, + Count } } \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Handles/HSharedMem.cs b/Ryujinx.HLE/OsHle/Handles/HSharedMem.cs deleted file mode 100644 index cd3d82237c..0000000000 --- a/Ryujinx.HLE/OsHle/Handles/HSharedMem.cs +++ /dev/null @@ -1,44 +0,0 @@ -using ChocolArm64.Memory; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.OsHle.Handles -{ - class HSharedMem - { - private List<(AMemory, long, long)> Positions; - - public EventHandler MemoryMapped; - public EventHandler MemoryUnmapped; - - public HSharedMem() - { - Positions = new List<(AMemory, long, long)>(); - } - - public void AddVirtualPosition(AMemory Memory, long Position, long Size) - { - lock (Positions) - { - Positions.Add((Memory, Position, Size)); - - MemoryMapped?.Invoke(this, EventArgs.Empty); - } - } - - public void RemoveVirtualPosition(AMemory Memory, long Position, long Size) - { - lock (Positions) - { - Positions.Remove((Memory, Position, Size)); - - MemoryUnmapped?.Invoke(this, EventArgs.Empty); - } - } - - public (AMemory, long, long)[] GetVirtualPositions() - { - return Positions.ToArray(); - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/OsHle/Horizon.cs b/Ryujinx.HLE/OsHle/Horizon.cs index d399d72b16..02f9a1c6ae 100644 --- a/Ryujinx.HLE/OsHle/Horizon.cs +++ b/Ryujinx.HLE/OsHle/Horizon.cs @@ -1,6 +1,7 @@ using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Npdm; using Ryujinx.HLE.Logging; +using Ryujinx.HLE.OsHle.Font; using Ryujinx.HLE.OsHle.Handles; using Ryujinx.HLE.OsHle.SystemState; using System; @@ -25,6 +26,8 @@ namespace Ryujinx.HLE.OsHle internal KSharedMemory HidSharedMem { get; private set; } internal KSharedMemory FontSharedMem { get; private set; } + internal SharedFontManager Font { get; private set; } + internal KEvent VsyncEvent { get; private set; } public Horizon(Switch Ns) @@ -46,6 +49,8 @@ namespace Ryujinx.HLE.OsHle HidSharedMem = new KSharedMemory(HidPA, HidSize); FontSharedMem = new KSharedMemory(FontPA, FontSize); + Font = new SharedFontManager(Ns, FontSharedMem.PA); + VsyncEvent = new KEvent(); } diff --git a/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs b/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs index b8447ac65c..4788c5aff8 100644 --- a/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs +++ b/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.Font; +using Ryujinx.HLE.OsHle.Font; using Ryujinx.HLE.OsHle.Ipc; using System.Collections.Generic; @@ -27,8 +27,8 @@ namespace Ryujinx.HLE.OsHle.Services.Pl { SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32(); - Context.Ns.Font.Load(FontType); - + //We don't need to do anything here because we do lazy initialization + //on SharedFontManager (the font is loaded when necessary). return 0; } @@ -36,7 +36,9 @@ namespace Ryujinx.HLE.OsHle.Services.Pl { SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32(); - Context.ResponseData.Write(Context.Ns.Font.GetLoadState(FontType)); + //1 (true) indicates that the font is already loaded. + //All fonts are already loaded. + Context.ResponseData.Write(1); return 0; } @@ -45,7 +47,7 @@ namespace Ryujinx.HLE.OsHle.Services.Pl { SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32(); - Context.ResponseData.Write(Context.Ns.Font.GetFontSize(FontType)); + Context.ResponseData.Write(Context.Ns.Os.Font.GetFontSize(FontType)); return 0; } @@ -54,13 +56,15 @@ namespace Ryujinx.HLE.OsHle.Services.Pl { SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32(); - Context.ResponseData.Write(Context.Ns.Font.GetSharedMemoryAddressOffset(FontType)); + Context.ResponseData.Write(Context.Ns.Os.Font.GetSharedMemoryAddressOffset(FontType)); return 0; } public long GetSharedMemoryNativeHandle(ServiceCtx Context) { + Context.Ns.Os.Font.EnsureInitialized(); + int Handle = Context.Process.HandleTable.OpenHandle(Context.Ns.Os.FontSharedMem); Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle); @@ -68,50 +72,54 @@ namespace Ryujinx.HLE.OsHle.Services.Pl return 0; } - private uint AddFontToOrderOfPriorityList(ServiceCtx Context, SharedFontType FontType, uint BufferPos, out uint LoadState) + public long GetSharedFontInOrderOfPriority(ServiceCtx Context) { - long TypesPosition = Context.Request.ReceiveBuff[0].Position; - long TypesSize = Context.Request.ReceiveBuff[0].Size; + long LanguageCode = Context.RequestData.ReadInt64(); + int LoadedCount = 0; - long OffsetsPosition = Context.Request.ReceiveBuff[1].Position; - long OffsetsSize = Context.Request.ReceiveBuff[1].Size; + for (SharedFontType Type = 0; Type < SharedFontType.Count; Type++) + { + int Offset = (int)Type * 4; + + if (!AddFontToOrderOfPriorityList(Context, (SharedFontType)Type, Offset)) + { + break; + } + + LoadedCount++; + } + + Context.ResponseData.Write(LoadedCount); + Context.ResponseData.Write((int)SharedFontType.Count); + + return 0; + } + + private bool AddFontToOrderOfPriorityList(ServiceCtx Context, SharedFontType FontType, int Offset) + { + long TypesPosition = Context.Request.ReceiveBuff[0].Position; + long TypesSize = Context.Request.ReceiveBuff[0].Size; + + long OffsetsPosition = Context.Request.ReceiveBuff[1].Position; + long OffsetsSize = Context.Request.ReceiveBuff[1].Size; long FontSizeBufferPosition = Context.Request.ReceiveBuff[2].Position; long FontSizeBufferSize = Context.Request.ReceiveBuff[2].Size; - LoadState = Context.Ns.Font.GetLoadState(FontType); - - if (BufferPos >= TypesSize || BufferPos >= OffsetsSize || BufferPos >= FontSizeBufferSize) + if ((uint)Offset + 4 > (uint)TypesSize || + (uint)Offset + 4 > (uint)OffsetsSize || + (uint)Offset + 4 > (uint)FontSizeBufferSize) { - return 0; + return false; } - Context.Memory.WriteUInt32(TypesPosition + BufferPos, (uint)FontType); - Context.Memory.WriteUInt32(OffsetsPosition + BufferPos, Context.Ns.Font.GetSharedMemoryAddressOffset(FontType)); - Context.Memory.WriteUInt32(FontSizeBufferPosition + BufferPos, Context.Ns.Font.GetFontSize(FontType)); + Context.Memory.WriteInt32(TypesPosition + Offset, (int)FontType); - BufferPos += 4; + Context.Memory.WriteInt32(OffsetsPosition + Offset, Context.Ns.Os.Font.GetSharedMemoryAddressOffset(FontType)); - return BufferPos; - } + Context.Memory.WriteInt32(FontSizeBufferPosition + Offset, Context.Ns.Os.Font.GetFontSize(FontType)); - public long GetSharedFontInOrderOfPriority(ServiceCtx Context) - { - ulong LanguageCode = Context.RequestData.ReadUInt64(); - uint LoadedCount = 0; - uint BufferPos = 0; - uint Loaded = 0; - - for (int Type = 0; Type < Context.Ns.Font.Count; Type++) - { - BufferPos = AddFontToOrderOfPriorityList(Context, (SharedFontType)Type, BufferPos, out Loaded); - LoadedCount += Loaded; - } - - Context.ResponseData.Write(LoadedCount); - Context.ResponseData.Write(Context.Ns.Font.Count); - - return 0; + return true; } } } \ No newline at end of file diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index a11d584695..165922e904 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -1,6 +1,5 @@ using Ryujinx.Audio; using Ryujinx.Graphics.Gal; -using Ryujinx.HLE.Font; using Ryujinx.HLE.Gpu; using Ryujinx.HLE.Input; using Ryujinx.HLE.Logging; @@ -28,8 +27,6 @@ namespace Ryujinx.HLE public Hid Hid { get; private set; } - public SharedFontManager Font { get; private set; } - public event EventHandler Finish; public Switch(IGalRenderer Renderer, IAalOutput AudioOut)