SharedFontManager.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. using ChocolArm64.Exceptions;
  2. using ChocolArm64.Memory;
  3. using Ryujinx.HLE.Logging;
  4. using Ryujinx.HLE.OsHle;
  5. using Ryujinx.HLE.OsHle.Handles;
  6. using Ryujinx.HLE.Resource;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.IO;
  10. namespace Ryujinx.HLE.Font
  11. {
  12. public class SharedFontManager
  13. {
  14. private const uint SharedMemorySize = 0x1100000;
  15. private Logger Log;
  16. private string FontsPath;
  17. private object ShMemLock;
  18. private (AMemory, long, long)[] ShMemPositions;
  19. private Dictionary<SharedFontType, byte[]> FontData;
  20. private uint[] LoadedFonts;
  21. public SharedFontManager(Logger Log, string SystemPath)
  22. {
  23. this.Log = Log;
  24. this.FontsPath = Path.Combine(SystemPath, "fonts");
  25. ShMemLock = new object();
  26. ShMemPositions = new(AMemory, long, long)[0];
  27. FontData = new Dictionary<SharedFontType, byte[]>()
  28. {
  29. { SharedFontType.JapanUsEurope, GetData("FontStandard") },
  30. { SharedFontType.SimplifiedChinese, GetData("FontChineseSimplified") },
  31. { SharedFontType.SimplifiedChineseEx, GetData("FontExtendedChineseSimplified") },
  32. { SharedFontType.TraditionalChinese, GetData("FontChineseTraditional") },
  33. { SharedFontType.Korean, GetData("FontKorean") },
  34. { SharedFontType.NintendoEx, GetData("FontNintendoExtended") }
  35. };
  36. int FontMemoryUsage = 0;
  37. foreach (byte[] data in FontData.Values)
  38. {
  39. FontMemoryUsage += data.Length;
  40. FontMemoryUsage += 0x8;
  41. }
  42. if (FontMemoryUsage > SharedMemorySize)
  43. {
  44. 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)");
  45. }
  46. LoadedFonts = new uint[FontData.Count];
  47. }
  48. public byte[] GetData(string FontName)
  49. {
  50. string FontFilePath = Path.Combine(FontsPath, $"{FontName}.ttf");
  51. if (File.Exists(FontFilePath))
  52. {
  53. return File.ReadAllBytes(FontFilePath);
  54. }
  55. else
  56. {
  57. throw new InvalidSystemResourceException($"Font \"{FontName}.ttf\" not found. Please provide it in \"{FontsPath}\".");
  58. }
  59. }
  60. public void MapFont(SharedFontType FontType, AMemory Memory, long Position)
  61. {
  62. uint SharedMemoryAddressOffset = GetSharedMemoryAddressOffset(FontType);
  63. // TODO: find what are the 8 bytes before the font
  64. Memory.WriteUInt64(Position + SharedMemoryAddressOffset - 8, 0);
  65. Memory.WriteBytes(Position + SharedMemoryAddressOffset, FontData[FontType]);
  66. }
  67. public void PropagateNewMapFont(SharedFontType Type)
  68. {
  69. lock (ShMemLock)
  70. {
  71. foreach ((AMemory Memory, long Position, long Size) in ShMemPositions)
  72. {
  73. AMemoryMapInfo MemoryInfo = Memory.Manager.GetMapInfo(Position);
  74. if (MemoryInfo == null)
  75. {
  76. throw new VmmPageFaultException(Position);
  77. }
  78. // The memory is read only, we need to changes that to add the new font
  79. AMemoryPerm originalPerms = MemoryInfo.Perm;
  80. Memory.Manager.Reprotect(Position, Size, AMemoryPerm.RW);
  81. MapFont(Type, Memory, Position);
  82. Memory.Manager.Reprotect(Position, Size, originalPerms);
  83. }
  84. }
  85. }
  86. internal void ShMemMap(object sender, EventArgs e)
  87. {
  88. HSharedMem SharedMem = (HSharedMem)sender;
  89. lock (ShMemLock)
  90. {
  91. ShMemPositions = SharedMem.GetVirtualPositions();
  92. (AMemory Memory, long Position, long Size) = ShMemPositions[ShMemPositions.Length - 1];
  93. for (int Type = 0; Type < LoadedFonts.Length; Type++)
  94. {
  95. if (LoadedFonts[(int)Type] == 1)
  96. {
  97. MapFont((SharedFontType)Type, Memory, Position);
  98. }
  99. }
  100. }
  101. }
  102. internal void ShMemUnmap(object sender, EventArgs e)
  103. {
  104. HSharedMem SharedMem = (HSharedMem)sender;
  105. lock (ShMemLock)
  106. {
  107. ShMemPositions = SharedMem.GetVirtualPositions();
  108. }
  109. }
  110. public void Load(SharedFontType FontType)
  111. {
  112. if (LoadedFonts[(int)FontType] == 0)
  113. {
  114. PropagateNewMapFont(FontType);
  115. }
  116. LoadedFonts[(int)FontType] = 1;
  117. }
  118. public uint GetLoadState(SharedFontType FontType)
  119. {
  120. if (LoadedFonts[(int)FontType] != 1)
  121. {
  122. // Some games don't request a load, so we need to load it here.
  123. Load(FontType);
  124. return 0;
  125. }
  126. return LoadedFonts[(int)FontType];
  127. }
  128. public uint GetFontSize(SharedFontType FontType)
  129. {
  130. return (uint)FontData[FontType].Length;
  131. }
  132. public uint GetSharedMemoryAddressOffset(SharedFontType FontType)
  133. {
  134. uint Pos = 0x8;
  135. for (SharedFontType Type = SharedFontType.JapanUsEurope; Type < FontType; Type++)
  136. {
  137. Pos += GetFontSize(Type);
  138. Pos += 0x8;
  139. }
  140. return Pos;
  141. }
  142. public int Count => FontData.Count;
  143. }
  144. }