aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.HLE/Font/SharedFontManager.cs177
-rw-r--r--Ryujinx.HLE/Font/SharedFontType.cs (renamed from Ryujinx.HLE/OsHle/Services/Pl/SharedFontType.cs)4
-rw-r--r--Ryujinx.HLE/Hid/Hid.cs10
-rw-r--r--Ryujinx.HLE/Logging/LogClass.cs1
-rw-r--r--Ryujinx.HLE/OsHle/Handles/HSharedMem.cs14
-rw-r--r--Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs8
-rw-r--r--Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs10
-rw-r--r--Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs1
-rw-r--r--Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs72
-rw-r--r--Ryujinx.HLE/Resource/InvalidSystemResourceException.cs13
-rw-r--r--Ryujinx.HLE/Ryujinx.HLE.csproj2
-rw-r--r--Ryujinx.HLE/Switch.cs12
-rw-r--r--Ryujinx.HLE/VirtualFileSystem.cs3
13 files changed, 292 insertions, 35 deletions
diff --git a/Ryujinx.HLE/Font/SharedFontManager.cs b/Ryujinx.HLE/Font/SharedFontManager.cs
new file mode 100644
index 00000000..fce270de
--- /dev/null
+++ b/Ryujinx.HLE/Font/SharedFontManager.cs
@@ -0,0 +1,177 @@
+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<SharedFontType, byte[]> 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, byte[]>()
+ {
+ { 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/OsHle/Services/Pl/SharedFontType.cs b/Ryujinx.HLE/Font/SharedFontType.cs
index 97fd95dc..ca8a42b0 100644
--- a/Ryujinx.HLE/OsHle/Services/Pl/SharedFontType.cs
+++ b/Ryujinx.HLE/Font/SharedFontType.cs
@@ -1,6 +1,6 @@
-namespace Ryujinx.HLE.OsHle.Services.Pl
+namespace Ryujinx.HLE.Font
{
- enum SharedFontType
+ public enum SharedFontType
{
JapanUsEurope = 0,
SimplifiedChinese = 1,
diff --git a/Ryujinx.HLE/Hid/Hid.cs b/Ryujinx.HLE/Hid/Hid.cs
index 2f007f1f..43c040bb 100644
--- a/Ryujinx.HLE/Hid/Hid.cs
+++ b/Ryujinx.HLE/Hid/Hid.cs
@@ -67,7 +67,7 @@ namespace Ryujinx.HLE.Input
private object ShMemLock;
- private (AMemory, long)[] ShMemPositions;
+ private (AMemory, long, long)[] ShMemPositions;
public Hid(Logger Log)
{
@@ -75,7 +75,7 @@ namespace Ryujinx.HLE.Input
ShMemLock = new object();
- ShMemPositions = new (AMemory, long)[0];
+ ShMemPositions = new (AMemory, long, long)[0];
}
internal void ShMemMap(object sender, EventArgs e)
@@ -86,7 +86,7 @@ namespace Ryujinx.HLE.Input
{
ShMemPositions = SharedMem.GetVirtualPositions();
- (AMemory Memory, long Position) = ShMemPositions[ShMemPositions.Length - 1];
+ (AMemory Memory, long Position, long Size) = ShMemPositions[ShMemPositions.Length - 1];
for (long Offset = 0; Offset < Horizon.HidSize; Offset += 8)
{
@@ -167,7 +167,7 @@ namespace Ryujinx.HLE.Input
{
lock (ShMemLock)
{
- foreach ((AMemory Memory, long Position) in ShMemPositions)
+ foreach ((AMemory Memory, long Position, long Size) in ShMemPositions)
{
long ControllerOffset = Position + HidControllersOffset;
@@ -218,7 +218,7 @@ namespace Ryujinx.HLE.Input
{
lock (ShMemLock)
{
- foreach ((AMemory Memory, long Position) in ShMemPositions)
+ foreach ((AMemory Memory, long Position, long Size) in ShMemPositions)
{
long TouchScreenOffset = Position + HidTouchScreenOffset;
diff --git a/Ryujinx.HLE/Logging/LogClass.cs b/Ryujinx.HLE/Logging/LogClass.cs
index c377ace6..95cae7e0 100644
--- a/Ryujinx.HLE/Logging/LogClass.cs
+++ b/Ryujinx.HLE/Logging/LogClass.cs
@@ -4,6 +4,7 @@ namespace Ryujinx.HLE.Logging
{
Audio,
Cpu,
+ Font,
Gpu,
Hid,
Kernel,
diff --git a/Ryujinx.HLE/OsHle/Handles/HSharedMem.cs b/Ryujinx.HLE/OsHle/Handles/HSharedMem.cs
index 6426e585..cd3d8223 100644
--- a/Ryujinx.HLE/OsHle/Handles/HSharedMem.cs
+++ b/Ryujinx.HLE/OsHle/Handles/HSharedMem.cs
@@ -6,37 +6,37 @@ namespace Ryujinx.HLE.OsHle.Handles
{
class HSharedMem
{
- private List<(AMemory, long)> Positions;
+ private List<(AMemory, long, long)> Positions;
public EventHandler<EventArgs> MemoryMapped;
public EventHandler<EventArgs> MemoryUnmapped;
public HSharedMem()
{
- Positions = new List<(AMemory, long)>();
+ Positions = new List<(AMemory, long, long)>();
}
- public void AddVirtualPosition(AMemory Memory, long Position)
+ public void AddVirtualPosition(AMemory Memory, long Position, long Size)
{
lock (Positions)
{
- Positions.Add((Memory, Position));
+ Positions.Add((Memory, Position, Size));
MemoryMapped?.Invoke(this, EventArgs.Empty);
}
}
- public void RemoveVirtualPosition(AMemory Memory, long Position)
+ public void RemoveVirtualPosition(AMemory Memory, long Position, long Size)
{
lock (Positions)
{
- Positions.Remove((Memory, Position));
+ Positions.Remove((Memory, Position, Size));
MemoryUnmapped?.Invoke(this, EventArgs.Empty);
}
}
- public (AMemory, long)[] GetVirtualPositions()
+ public (AMemory, long, long)[] GetVirtualPositions()
{
return Positions.ToArray();
}
diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs b/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs
index e816c44e..6f7bc42f 100644
--- a/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs
+++ b/Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs
@@ -22,7 +22,7 @@ namespace Ryujinx.HLE.OsHle.Kernel
private ConcurrentDictionary<KThread, AutoResetEvent> SyncWaits;
- private HashSet<(HSharedMem, long)> MappedSharedMems;
+ private HashSet<(HSharedMem, long, long)> MappedSharedMems;
private ulong CurrentHeapSize;
@@ -83,7 +83,7 @@ namespace Ryujinx.HLE.OsHle.Kernel
SyncWaits = new ConcurrentDictionary<KThread, AutoResetEvent>();
- MappedSharedMems = new HashSet<(HSharedMem, long)>();
+ MappedSharedMems = new HashSet<(HSharedMem, long, long)>();
}
static SvcHandler()
@@ -138,9 +138,9 @@ namespace Ryujinx.HLE.OsHle.Kernel
{
lock (MappedSharedMems)
{
- foreach ((HSharedMem SharedMem, long Position) in MappedSharedMems)
+ foreach ((HSharedMem SharedMem, long Position, long Size) in MappedSharedMems)
{
- SharedMem.RemoveVirtualPosition(Memory, Position);
+ SharedMem.RemoveVirtualPosition(Memory, Position, Size);
}
MappedSharedMems.Clear();
diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs b/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs
index bb73f1ea..f10cad7a 100644
--- a/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs
+++ b/Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs
@@ -174,15 +174,15 @@ namespace Ryujinx.HLE.OsHle.Kernel
AMemoryHelper.FillWithZeros(Memory, Src, (int)Size);
+ SharedMem.AddVirtualPosition(Memory, Src, Size);
+
Memory.Manager.Reprotect(Src, Size, (AMemoryPerm)Perm);
lock (MappedSharedMems)
{
- MappedSharedMems.Add((SharedMem, Src));
+ MappedSharedMems.Add((SharedMem, Src, Size));
}
- SharedMem.AddVirtualPosition(Memory, Src);
-
ThreadState.X0 = 0;
}
@@ -210,11 +210,11 @@ namespace Ryujinx.HLE.OsHle.Kernel
{
Memory.Manager.Unmap(Src, Size, (int)MemoryType.SharedMemory);
- SharedMem.RemoveVirtualPosition(Memory, Src);
+ SharedMem.RemoveVirtualPosition(Memory, Src, Size);
lock (MappedSharedMems)
{
- MappedSharedMems.Remove((SharedMem, Src));
+ MappedSharedMems.Remove((SharedMem, Src, Size));
}
ThreadState.X0 = 0;
diff --git a/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs b/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs
index 08305522..a968a1db 100644
--- a/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs
+++ b/Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs
@@ -242,7 +242,6 @@ namespace Ryujinx.HLE.OsHle.Kernel
Process.Scheduler.Suspend(CurrThread);
IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr);
-
long Result = IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr);
Thread.Yield();
diff --git a/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs b/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs
index 9f85f3d1..b8447ac6 100644
--- a/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs
+++ b/Ryujinx.HLE/OsHle/Services/Pl/ISharedFontManager.cs
@@ -1,3 +1,4 @@
+using Ryujinx.HLE.Font;
using Ryujinx.HLE.OsHle.Ipc;
using System.Collections.Generic;
@@ -13,11 +14,12 @@ namespace Ryujinx.HLE.OsHle.Services.Pl
{
m_Commands = new Dictionary<int, ServiceProcessRequest>()
{
- { 0, RequestLoad },
- { 1, GetLoadState },
- { 2, GetFontSize },
- { 3, GetSharedMemoryAddressOffset },
- { 4, GetSharedMemoryNativeHandle }
+ { 0, RequestLoad },
+ { 1, GetLoadState },
+ { 2, GetFontSize },
+ { 3, GetSharedMemoryAddressOffset },
+ { 4, GetSharedMemoryNativeHandle },
+ { 5, GetSharedFontInOrderOfPriority }
};
}
@@ -25,26 +27,34 @@ namespace Ryujinx.HLE.OsHle.Services.Pl
{
SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32();
+ Context.Ns.Font.Load(FontType);
+
return 0;
}
public long GetLoadState(ServiceCtx Context)
{
- Context.ResponseData.Write(1); //Loaded
+ SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32();
+
+ Context.ResponseData.Write(Context.Ns.Font.GetLoadState(FontType));
return 0;
}
public long GetFontSize(ServiceCtx Context)
{
- Context.ResponseData.Write(Horizon.FontSize);
+ SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32();
+
+ Context.ResponseData.Write(Context.Ns.Font.GetFontSize(FontType));
return 0;
}
public long GetSharedMemoryAddressOffset(ServiceCtx Context)
{
- Context.ResponseData.Write(0);
+ SharedFontType FontType = (SharedFontType)Context.RequestData.ReadInt32();
+
+ Context.ResponseData.Write(Context.Ns.Font.GetSharedMemoryAddressOffset(FontType));
return 0;
}
@@ -57,5 +67,51 @@ namespace Ryujinx.HLE.OsHle.Services.Pl
return 0;
}
+
+ private uint AddFontToOrderOfPriorityList(ServiceCtx Context, SharedFontType FontType, uint BufferPos, out uint LoadState)
+ {
+ 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)
+ {
+ return 0;
+ }
+
+ 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));
+
+ BufferPos += 4;
+
+ return BufferPos;
+ }
+
+ 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;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/Resource/InvalidSystemResourceException.cs b/Ryujinx.HLE/Resource/InvalidSystemResourceException.cs
new file mode 100644
index 00000000..35c4874a
--- /dev/null
+++ b/Ryujinx.HLE/Resource/InvalidSystemResourceException.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Ryujinx.HLE.Resource
+{
+ public class InvalidSystemResourceException : Exception
+ {
+ public InvalidSystemResourceException(string message)
+ : base(message)
+ {
+ }
+
+ }
+}
diff --git a/Ryujinx.HLE/Ryujinx.HLE.csproj b/Ryujinx.HLE/Ryujinx.HLE.csproj
index acef4be9..f7fb84a5 100644
--- a/Ryujinx.HLE/Ryujinx.HLE.csproj
+++ b/Ryujinx.HLE/Ryujinx.HLE.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs
index 74c0564a..a80ca86c 100644
--- a/Ryujinx.HLE/Switch.cs
+++ b/Ryujinx.HLE/Switch.cs
@@ -1,5 +1,6 @@
using Ryujinx.Audio;
using Ryujinx.Graphics.Gal;
+using Ryujinx.HLE.Font;
using Ryujinx.HLE.Gpu;
using Ryujinx.HLE.Input;
using Ryujinx.HLE.Logging;
@@ -27,6 +28,8 @@ 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)
@@ -57,8 +60,13 @@ namespace Ryujinx.HLE
Hid = new Hid(Log);
- Os.HidSharedMem.MemoryMapped += Hid.ShMemMap;
- Os.HidSharedMem.MemoryUnmapped += Hid.ShMemUnmap;
+ Font = new SharedFontManager(Log, VFs.GetSystemPath());
+
+ Os.HidSharedMem.MemoryMapped += Hid.ShMemMap;
+ Os.HidSharedMem.MemoryUnmapped += Hid.ShMemUnmap;
+
+ Os.FontSharedMem.MemoryMapped += Font.ShMemMap;
+ Os.FontSharedMem.MemoryUnmapped += Font.ShMemUnmap;
}
public void LoadCart(string ExeFsDir, string RomFsFile = null)
diff --git a/Ryujinx.HLE/VirtualFileSystem.cs b/Ryujinx.HLE/VirtualFileSystem.cs
index df1fc9db..31b8e184 100644
--- a/Ryujinx.HLE/VirtualFileSystem.cs
+++ b/Ryujinx.HLE/VirtualFileSystem.cs
@@ -8,6 +8,7 @@ namespace Ryujinx.HLE
private const string BasePath = "RyuFs";
private const string NandPath = "nand";
private const string SdCardPath = "sdmc";
+ private const string SystemPath = "system";
public Stream RomFs { get; private set; }
@@ -45,6 +46,8 @@ namespace Ryujinx.HLE
public string GetGameSavesPath() => MakeDirAndGetFullPath(NandPath);
+ public string GetSystemPath() => MakeDirAndGetFullPath(SystemPath);
+
public string SwitchPathToSystemPath(string SwitchPath)
{
string[] Parts = SwitchPath.Split(":");