Integrate shared font support

This commit is contained in:
gdkchan 2018-08-05 02:07:20 -03:00
parent fd1d68db34
commit c23dc434f8
10 changed files with 198 additions and 270 deletions

View file

@ -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)

View file

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

View file

@ -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,

View file

@ -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);

View file

@ -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<SharedFontType, FontInfo> 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, FontInfo>()
{
{ 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;
}
}
}

View file

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

View file

@ -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<EventArgs> MemoryMapped;
public EventHandler<EventArgs> 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();
}
}
}

View file

@ -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();
}

View file

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

View file

@ -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)