Skip to content

Commit

Permalink
Implement Shared Fonts (#215)
Browse files Browse the repository at this point in the history
* Implement Shared Fonts

This fully implements shared fonts.
This commit is provided without fonts.
This commit also add Size to HSharedMem.Positions to be able to add fonts to shared zones when RequestLoad is called.

* Require the user to provide fonts in RyuFS/system

* Use File.Exits instead of relying ona try/catch and change system resource exception format a bit

* Make sure that font sum doesn't exceed 17MB

Also rename font data dictionary for coherence.
  • Loading branch information
marysaka authored and gdkchan committed Aug 4, 2018
1 parent 5f34353 commit eeb6269
Show file tree
Hide file tree
Showing 13 changed files with 292 additions and 35 deletions.
177 changes: 177 additions & 0 deletions Ryujinx.HLE/Font/SharedFontManager.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Ryujinx.HLE.OsHle.Services.Pl
namespace Ryujinx.HLE.Font
{
enum SharedFontType
public enum SharedFontType
{
JapanUsEurope = 0,
SimplifiedChinese = 1,
Expand Down
10 changes: 5 additions & 5 deletions Ryujinx.HLE/Hid/Hid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,15 @@ public class Hid

private object ShMemLock;

private (AMemory, long)[] ShMemPositions;
private (AMemory, long, long)[] ShMemPositions;

public Hid(Logger Log)
{
this.Log = Log;

ShMemLock = new object();

ShMemPositions = new (AMemory, long)[0];
ShMemPositions = new (AMemory, long, long)[0];
}

internal void ShMemMap(object sender, EventArgs e)
Expand All @@ -86,7 +86,7 @@ internal void ShMemMap(object sender, EventArgs e)
{
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)
{
Expand Down Expand Up @@ -167,7 +167,7 @@ public void SetJoyconButton(
{
lock (ShMemLock)
{
foreach ((AMemory Memory, long Position) in ShMemPositions)
foreach ((AMemory Memory, long Position, long Size) in ShMemPositions)
{
long ControllerOffset = Position + HidControllersOffset;

Expand Down Expand Up @@ -218,7 +218,7 @@ public void SetTouchPoints(params HidTouchPoint[] Points)
{
lock (ShMemLock)
{
foreach ((AMemory Memory, long Position) in ShMemPositions)
foreach ((AMemory Memory, long Position, long Size) in ShMemPositions)
{
long TouchScreenOffset = Position + HidTouchScreenOffset;

Expand Down
1 change: 1 addition & 0 deletions Ryujinx.HLE/Logging/LogClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ public enum LogClass
{
Audio,
Cpu,
Font,
Gpu,
Hid,
Kernel,
Expand Down
14 changes: 7 additions & 7 deletions Ryujinx.HLE/OsHle/Handles/HSharedMem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
8 changes: 4 additions & 4 deletions Ryujinx.HLE/OsHle/Kernel/SvcHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ partial class SvcHandler : IDisposable

private ConcurrentDictionary<KThread, AutoResetEvent> SyncWaits;

private HashSet<(HSharedMem, long)> MappedSharedMems;
private HashSet<(HSharedMem, long, long)> MappedSharedMems;

private ulong CurrentHeapSize;

Expand Down Expand Up @@ -83,7 +83,7 @@ public SvcHandler(Switch Ns, Process Process)

SyncWaits = new ConcurrentDictionary<KThread, AutoResetEvent>();

MappedSharedMems = new HashSet<(HSharedMem, long)>();
MappedSharedMems = new HashSet<(HSharedMem, long, long)>();
}

static SvcHandler()
Expand Down Expand Up @@ -138,9 +138,9 @@ protected virtual void Dispose(bool Disposing)
{
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();
Expand Down
10 changes: 5 additions & 5 deletions Ryujinx.HLE/OsHle/Kernel/SvcMemory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,15 @@ private void SvcMapSharedMemory(AThreadState ThreadState)

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;
}

Expand Down Expand Up @@ -210,11 +210,11 @@ private void SvcUnmapSharedMemory(AThreadState ThreadState)
{
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;
Expand Down
1 change: 0 additions & 1 deletion Ryujinx.HLE/OsHle/Kernel/SvcSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,6 @@ private void SendSyncRequest(AThreadState ThreadState, long CmdPtr, long Size, i
Process.Scheduler.Suspend(CurrThread);

IpcMessage Cmd = new IpcMessage(CmdData, CmdPtr);

long Result = IpcHandler.IpcCall(Ns, Process, Memory, Session, Cmd, CmdPtr);

Thread.Yield();
Expand Down
Loading

0 comments on commit eeb6269

Please sign in to comment.