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:
Thog 2018-07-02 22:23:52 +02:00
parent ce96a45685
commit 3277d3020f
No known key found for this signature in database
GPG key ID: 0CD291558FAFDBC6
12 changed files with 285 additions and 35 deletions

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

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

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.OsHle.Services.Pl
namespace Ryujinx.HLE.Font
{
enum SharedFontType
public enum SharedFontType
{
JapanUsEurope = 0,
SimplifiedChinese = 1,

View file

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

View file

@ -4,6 +4,7 @@ namespace Ryujinx.HLE.Logging
{
Audio,
Cpu,
Font,
Gpu,
Hid,
Kernel,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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" />

View file

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