Implement Shared Fonts
This fully implements shared fonts. This commit is provided without fonts and therefore cannot compile as it is. This commit also add Size to HSharedMem.Positions to be able to add fonts to shared zones when RequestLoad is called.
This commit is contained in:
parent
ce96a45685
commit
3277d3020f
12 changed files with 285 additions and 35 deletions
19
Ryujinx.HLE/Font/EmbeddedResource.cs
Normal file
19
Ryujinx.HLE/Font/EmbeddedResource.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Ryujinx.HLE.Font
|
||||
{
|
||||
static class EmbeddedResource
|
||||
{
|
||||
public static byte[] GetData(string Name)
|
||||
{
|
||||
Assembly Asm = typeof(EmbeddedResource).Assembly;
|
||||
|
||||
using (Stream ResStream = Asm.GetManifestResourceStream(Name))
|
||||
{
|
||||
BinaryReader Reader = new BinaryReader(ResStream);
|
||||
return Reader.ReadBytes((int)Reader.BaseStream.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
146
Ryujinx.HLE/Font/SharedFontManager.cs
Normal file
146
Ryujinx.HLE/Font/SharedFontManager.cs
Normal file
|
@ -0,0 +1,146 @@
|
|||
using ChocolArm64.Exceptions;
|
||||
using ChocolArm64.Memory;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using Ryujinx.HLE.OsHle;
|
||||
using Ryujinx.HLE.OsHle.Handles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.Font
|
||||
{
|
||||
public class SharedFontManager
|
||||
{
|
||||
private Logger Log;
|
||||
|
||||
private object ShMemLock;
|
||||
|
||||
private (AMemory, long, long)[] ShMemPositions;
|
||||
|
||||
private Dictionary<SharedFontType, byte[]> FontEmbeddedPaths;
|
||||
|
||||
private uint[] LoadedFonts;
|
||||
|
||||
public SharedFontManager(Logger Log)
|
||||
{
|
||||
this.Log = Log;
|
||||
|
||||
ShMemLock = new object();
|
||||
|
||||
ShMemPositions = new(AMemory, long, long)[0];
|
||||
|
||||
FontEmbeddedPaths = new Dictionary<SharedFontType, byte[]>()
|
||||
{
|
||||
{ SharedFontType.JapanUsEurope, EmbeddedResource.GetData("FontStandard") },
|
||||
{ SharedFontType.SimplifiedChinese, EmbeddedResource.GetData("FontChineseSimplified") },
|
||||
{ SharedFontType.SimplifiedChineseEx, EmbeddedResource.GetData("FontExtendedChineseSimplified") },
|
||||
{ SharedFontType.TraditionalChinese, EmbeddedResource.GetData("FontChineseTraditional") },
|
||||
{ SharedFontType.Korean, EmbeddedResource.GetData("FontKorean") },
|
||||
{ SharedFontType.NintendoEx, EmbeddedResource.GetData("FontNintendoExtended") }
|
||||
};
|
||||
|
||||
LoadedFonts = new uint[FontEmbeddedPaths.Count];
|
||||
}
|
||||
|
||||
public void MapFont(SharedFontType FontType, AMemory Memory, long Position)
|
||||
{
|
||||
// TODO: find what are the 8 bytes before the font
|
||||
Memory.WriteBytes(Position + GetSharedMemoryAddressOffset(FontType), FontEmbeddedPaths[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 (SharedFontType Type = SharedFontType.JapanUsEurope; (int)Type < LoadedFonts.Length; Type++)
|
||||
{
|
||||
if (LoadedFonts[(int)Type] == 1)
|
||||
{
|
||||
MapFont(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 Convert.ToUInt32(FontEmbeddedPaths[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()
|
||||
{
|
||||
return FontEmbeddedPaths.Count;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace Ryujinx.HLE.OsHle.Services.Pl
|
||||
namespace Ryujinx.HLE.Font
|
||||
{
|
||||
enum SharedFontType
|
||||
public enum SharedFontType
|
||||
{
|
||||
JapanUsEurope = 0,
|
||||
SimplifiedChinese = 1,
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace Ryujinx.HLE.Logging
|
|||
{
|
||||
Audio,
|
||||
Cpu,
|
||||
Font,
|
||||
Gpu,
|
||||
Hid,
|
||||
Kernel,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 (SharedFontType Type = SharedFontType.JapanUsEurope; (int)Type < Context.Ns.Font.Count(); Type++)
|
||||
{
|
||||
BufferPos = AddFontToOrderOfPriorityList(Context, Type, BufferPos, out Loaded);
|
||||
LoadedCount += Loaded;
|
||||
}
|
||||
|
||||
Context.ResponseData.Write(LoadedCount);
|
||||
Context.ResponseData.Write(Context.Ns.Font.Count());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
|
@ -13,6 +13,27 @@
|
|||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Font\FontChineseSimplified.ttf">
|
||||
<LogicalName>FontChineseSimplified</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Font\FontChineseTraditional.ttf">
|
||||
<LogicalName>FontChineseTraditional</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Font\FontExtendedChineseSimplified.ttf">
|
||||
<LogicalName>FontExtendedChineseSimplified</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Font\FontKorean.ttf">
|
||||
<LogicalName>FontKorean</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Font\FontNintendoExtended.ttf">
|
||||
<LogicalName>FontNintendoExtended</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Font\FontStandard.ttf">
|
||||
<LogicalName>FontStandard</LogicalName>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
|
||||
|
|
|
@ -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);
|
||||
|
||||
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)
|
||||
|
|
Loading…
Add table
Reference in a new issue