2018-08-04 21:38:49 +00:00
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 ;
2018-08-09 08:02:27 +00:00
2018-08-04 21:38:49 +00:00
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" ) ;
2018-08-09 08:02:27 +00:00
2018-08-04 21:38:49 +00:00
if ( File . Exists ( FontFilePath ) )
{
return File . ReadAllBytes ( FontFilePath ) ;
}
else
{
2018-08-09 08:02:27 +00:00
Console . WriteLine ( $"Font \" { FontName } . ttf \ " not found. Please provide it in \"{FontsPath}\"." ) ;
return new byte [ 0 ] ;
2018-08-04 21:38:49 +00:00
}
}
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 ;
}
}