Libretro: Added libretro core

This commit is contained in:
Sour 2019-07-02 19:56:00 -04:00
parent f9e08d2c24
commit b5847a3d1f
32 changed files with 4096 additions and 43 deletions

1
.gitignore vendored
View File

@ -182,6 +182,5 @@ packages/*
!Libretro/hakchi/bin
Libretro/*
Docs/*
TestHelper/*

View File

@ -1,9 +1,16 @@
### Windows
1) Open the solution in VS2017
2) Compile as Release/x64 or Release/x86
2) Compile as Release/x64
3) Run
#### *Libretro*
1) Open the solution in VS2017
2) Compile as Libretro/x64
3) Use the "mesen-s_libretro.dll" file in bin/(x64 or x86)/Libretro/mesen-s_libretro.dll
### Linux
To compile Mesen-S under Linux you will need a recent version of clang/gcc. This is because Mesen-S requires a C++14 compiler, along with support for the filesystem API (C++17). Additionally, Mesen-S has the following dependencies:
@ -20,3 +27,12 @@ LTO is supported under clang, which gives a large performance boost (25-30%+), s
Examples:
`LTO=true make` will compile with clang and LTO.
`USE_GCC=true LTO=true make` will compile with gcc and LTO.
#### *Libretro*
To compile the libretro core you will need a recent version of clang/gcc. This is because Mesen-S requires a C++14 compiler, along with support for the filesystem API (C++17).
Running "make libretro" will build the core and put it in "bin/mesen-s_libretro.(x64 or x86).so".
LTO is supported under clang, which gives a large performance boost (25-30%+), so turning it on is highly recommended (see makefile for details).
**Note:** There is also another makefile in the Libretro folder - this is used by the RetroArch buildbot to build the core. You can also try using this makefile if you are having issues with the one in the root folder.

View File

@ -132,6 +132,19 @@ void Console::Run()
PlatformUtilities::RestoreTimerResolution();
}
void Console::RunSingleFrame()
{
//Used by Libretro
uint32_t lastFrameNumber = _ppu->GetFrameCount();
_emulationThreadId = std::this_thread::get_id();
while(_ppu->GetFrameCount() == lastFrameNumber) {
_cpu->Exec();
}
_controlManager->UpdateControlDevices();
}
void Console::Stop(bool sendNotification)
{
_stopFlag = true;
@ -213,6 +226,7 @@ void Console::PowerCycle()
RomInfo info = cart->GetRomInfo();
Lock();
LoadRom(info.RomFile, info.PatchFile, false);
_memoryManager->IncrementMasterClockValue<182>();
Unlock();
}
}
@ -229,15 +243,6 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom)
if(stopRom) {
Stop(false);
}
vector<uint8_t> spcRomData;
VirtualFile spcBios(FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "spc700.rom"));
if(spcBios.IsValid()) {
spcBios.ReadFile(spcRomData);
} else {
MessageManager::DisplayMessage("SPC", "spc700.rom not found, cannot launch game.");
return false;
}
_cart = cart;
UpdateRegion();
@ -247,7 +252,7 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom)
_internalRegisters.reset(new InternalRegisters(shared_from_this()));
_controlManager.reset(new ControlManager(shared_from_this()));
_dmaController.reset(new DmaController(_memoryManager.get()));
_spc.reset(new Spc(shared_from_this(), spcRomData));
_spc.reset(new Spc(shared_from_this()));
_memoryManager->Initialize(shared_from_this());

View File

@ -74,6 +74,7 @@ public:
void Release();
void Run();
void RunSingleFrame();
void Stop(bool sendNotification);
void Reset();

View File

@ -12,10 +12,9 @@
#include "Spc.h"
DummySpc::DummySpc(uint8_t *spcRam, uint8_t *spcRom, SpcState &state)
DummySpc::DummySpc(uint8_t *spcRam, SpcState &state)
{
_ram = spcRam;
_spcBios = spcRom;
_opCode = 0;
_opStep = SpcOpStep::ReadOpCode;
@ -34,7 +33,6 @@ DummySpc::DummySpc(uint8_t *spcRam, uint8_t *spcRom, SpcState &state)
DummySpc::~DummySpc()
{
_ram = nullptr;
_spcBios = nullptr;
}
void DummySpc::Step()

View File

@ -13,14 +13,27 @@ EmuSettings::EmuSettings()
uint32_t EmuSettings::GetVersion()
{
//0.1.0
return 0x00000100;
//Version 0.1.0
uint16_t major = 0;
uint8_t minor = 1;
uint8_t revision = 0;
return (major << 16) | (minor << 8) | revision;
}
string EmuSettings::GetVersionString()
{
uint32_t version = GetVersion();
return std::to_string(version >> 16) + "." + std::to_string((version >> 8) & 0xFF) + "." + std::to_string(version & 0xFF);
}
void EmuSettings::ProcessString(string & str, const char ** strPointer)
{
//Make a copy of the string and keep it (the original pointer will not be valid after the call is over)
str = *strPointer;
if(*strPointer) {
str = *strPointer;
} else {
str.clear();
}
*strPointer = str.c_str();
}
@ -180,17 +193,11 @@ uint32_t EmuSettings::GetEmulationSpeed()
}
}
double EmuSettings::GetAspectRatio()
double EmuSettings::GetAspectRatio(ConsoleRegion region)
{
switch(_video.AspectRatio) {
case VideoAspectRatio::NoStretching: return 0.0;
case VideoAspectRatio::Auto:
{
bool isPal = false;
return isPal ? (9440000.0 / 6384411.0) : (128.0 / 105.0);
}
case VideoAspectRatio::Auto: return region == ConsoleRegion::Pal ? (9440000.0 / 6384411.0) : (128.0 / 105.0);
case VideoAspectRatio::NTSC: return 128.0 / 105.0;
case VideoAspectRatio::PAL: return 9440000.0 / 6384411.0;
case VideoAspectRatio::Standard: return 4.0 / 3.0;

View File

@ -31,7 +31,9 @@ private:
public:
EmuSettings();
uint32_t GetVersion();
string GetVersionString();
void SetVideoConfig(VideoConfig config);
VideoConfig GetVideoConfig();
@ -56,7 +58,7 @@ public:
OverscanDimensions GetOverscan();
uint32_t GetRewindBufferSize();
uint32_t GetEmulationSpeed();
double GetAspectRatio();
double GetAspectRatio(ConsoleRegion region);
void SetFlag(EmulationFlags flag);
void SetFlagState(EmulationFlags flag, bool enabled);

View File

@ -1,4 +1,6 @@
#include "stdafx.h"
#ifndef LIBRETRO
#include "LuaApi.h"
#include "../Utilities/HexUtilities.h"
#include "../Utilities/FolderUtilities.h"
@ -703,3 +705,4 @@ int LuaApi::GetState(lua_State *lua)
return 1;
}
#endif

View File

@ -1,4 +1,5 @@
#include "stdafx.h"
#ifndef LIBRETRO
#include "LuaCallHelper.h"
LuaCallHelper::LuaCallHelper(lua_State *lua) : _lua(lua)
@ -145,3 +146,5 @@ int LuaCallHelper::ReturnCount()
{
return _returnCount;
}
#endif

View File

@ -1,4 +1,6 @@
#include "stdafx.h"
#ifndef LIBRETRO
#include "../Lua/lua.hpp"
#include "../Lua/luasocket.hpp"
#include "LuaScriptingContext.h"
@ -155,3 +157,4 @@ int LuaScriptingContext::InternalCallEventCallback(EventType type)
}
return l.ReturnCount();
}
#endif

View File

@ -1163,6 +1163,9 @@ void Ppu::SendFrame()
}
bool isRewinding = _console->GetRewindManager()->IsRewinding();
#ifdef LIBRETRO
_console->GetVideoDecoder()->UpdateFrameSync(_currentBuffer, width, height, _frameCount, isRewinding);
#else
if(isRewinding || _screenInterlace) {
_console->GetVideoDecoder()->UpdateFrameSync(_currentBuffer, width, height, _frameCount, isRewinding);
} else {
@ -1172,6 +1175,7 @@ void Ppu::SendFrame()
_currentBuffer = _currentBuffer == _outputBuffers[0] ? _outputBuffers[1] : _outputBuffers[0];
}
}
#endif
}
uint16_t* Ppu::GetScreenBuffer()

View File

@ -6,16 +6,13 @@
#include "SPC_DSP.h"
#include "../Utilities/Serializer.h"
Spc::Spc(shared_ptr<Console> console, vector<uint8_t> &spcRomData)
Spc::Spc(shared_ptr<Console> console)
{
_console = console;
_memoryManager = console->GetMemoryManager();
_soundBuffer = new int16_t[Spc::SampleBufferSize];
_ram = new uint8_t[Spc::SpcRamSize];
_spcBios = new uint8_t[Spc::SpcRomSize];
memcpy(_spcBios, spcRomData.data(), Spc::SpcRomSize);
memset(_ram, 0, Spc::SpcRamSize);
_dsp.reset(new SPC_DSP());
@ -47,7 +44,6 @@ Spc::~Spc()
{
delete[] _soundBuffer;
delete[] _ram;
delete[] _spcBios;
}
#endif

View File

@ -44,7 +44,16 @@ private:
SpcState _state;
uint8_t* _ram;
uint8_t* _spcBios;
uint8_t _spcBios[64] {
0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0,
0xFC, 0x8F, 0xAA, 0xF4, 0x8F, 0xBB, 0xF5, 0x78,
0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19, 0xEB, 0xF4,
0xD0, 0xFC, 0x7E, 0xF4, 0xD0, 0x0B, 0xE4, 0xF5,
0xCB, 0xF4, 0xD7, 0x00, 0xFC, 0xD0, 0xF3, 0xAB,
0x01, 0x10, 0xEF, 0x7E, 0xF4, 0x10, 0xEB, 0xBA,
0xF6, 0xDA, 0x00, 0xBA, 0xF4, 0xC4, 0xF4, 0xDD,
0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF
};
int16_t *_soundBuffer;
@ -268,7 +277,7 @@ private:
void Exec();
public:
Spc(shared_ptr<Console> console, vector<uint8_t> &spcRomData);
Spc(shared_ptr<Console> console);
virtual ~Spc();
void Run();
@ -305,7 +314,7 @@ private:
void LogWrite(uint32_t addr, uint8_t value);
public:
DummySpc(uint8_t *spcRam, uint8_t *spcRom, SpcState &state);
DummySpc(uint8_t *spcRam, SpcState &state);
void Step();

View File

@ -131,7 +131,7 @@ int32_t SpcDisUtils::GetEffectiveAddress(DisassemblyInfo &info, Console *console
{
if(_needAddress[info.GetOpCode()]) {
Spc* spc = console->GetSpc().get();
DummySpc dummySpc(spc->GetSpcRam(), spc->GetSpcRom(), state);
DummySpc dummySpc(spc->GetSpcRam(), state);
dummySpc.Step();
uint32_t addr;
uint8_t value;

View File

@ -39,7 +39,7 @@ ScreenSize VideoDecoder::GetScreenSize(bool ignoreScale)
ScreenSize size;
OverscanDimensions overscan = ignoreScale ? _videoFilter->GetOverscan() : _console->GetSettings()->GetOverscan();
FrameInfo frameInfo = _videoFilter->GetFrameInfo();
double aspectRatio = _console->GetSettings()->GetAspectRatio();
double aspectRatio = _console->GetSettings()->GetAspectRatio(_console->GetRegion());
double scale = (ignoreScale ? 1 : _console->GetSettings()->GetVideoConfig().VideoScale);
size.Width = (int32_t)(frameInfo.Width * scale / 2);
size.Height = (int32_t)(frameInfo.Height * scale / 2);

5
Libretro/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.a
*.so
*.dylib
*.bc
*.dll

265
Libretro/Libretro.vcxproj Normal file
View File

@ -0,0 +1,265 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Libretro|Win32">
<Configuration>Libretro</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Libretro|x64">
<Configuration>Libretro</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{4432139E-528B-44DE-961C-B37CD5E92E0E}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>Libretro</RootNamespace>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
<ProjectName>Libretro</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Libretro|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Libretro|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Libretro|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Libretro|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\</OutDir>
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
<TargetName>mesen-s_libretro</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Libretro|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\</OutDir>
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
<TargetName>mesen-s_libretro</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\</OutDir>
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
<TargetName>mesen-s_libretro</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\</OutDir>
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
<TargetName>mesen-s_libretro</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\</OutDir>
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
<TargetName>mesen-s_libretro</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Libretro|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\</OutDir>
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
<TargetName>mesen-s_libretro</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;LIBRETRO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableLanguageExtensions>true</DisableLanguageExtensions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Libretro|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;LIBRETRO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableLanguageExtensions>true</DisableLanguageExtensions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>Core.lib;Utilities.lib;SevenZip.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;LIBRETRO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DisableLanguageExtensions>true</DisableLanguageExtensions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;LIBRETRO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DisableLanguageExtensions>true</DisableLanguageExtensions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;LIBRETRO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableLanguageExtensions>true</DisableLanguageExtensions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Libretro|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;LIBRETRO_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableLanguageExtensions>true</DisableLanguageExtensions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>Core.lib;Utilities.lib;SevenZip.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="libretro.h" />
<ClInclude Include="LibretroKeyManager.h" />
<ClInclude Include="LibretroMessageManager.h" />
<ClInclude Include="LibretroRenderer.h" />
<ClInclude Include="LibretroSoundManager.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="libretro.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="libretro.h" />
<ClInclude Include="LibretroKeyManager.h" />
<ClInclude Include="LibretroMessageManager.h" />
<ClInclude Include="LibretroRenderer.h" />
<ClInclude Include="LibretroSoundManager.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="libretro.cpp" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,122 @@
#pragma once
#include "libretro.h"
#include "../Core/IKeyManager.h"
#include "../Core/KeyManager.h"
#include "../Core/Console.h"
class LibretroKeyManager : public IKeyManager
{
private:
shared_ptr<Console> _console;
retro_input_state_t _getInputState = nullptr;
retro_input_poll_t _pollInput = nullptr;
bool _mouseButtons[3] = { false, false, false };
bool _wasPushed[16] = { };
bool ProcessAction(uint32_t button)
{
if(_getInputState(0, RETRO_DEVICE_JOYPAD, 0, button)) {
if(!_wasPushed[button]) {
//Newly pressed, process action
_wasPushed[button] = true;
return true;
}
} else {
_wasPushed[button] = false;
}
return false;
}
public:
LibretroKeyManager(shared_ptr<Console> console)
{
_console = console;
KeyManager::RegisterKeyManager(this);
}
~LibretroKeyManager()
{
KeyManager::RegisterKeyManager(nullptr);
}
void SetGetInputState(retro_input_state_t getInputState)
{
_getInputState = getInputState;
}
void SetPollInput(retro_input_poll_t pollInput)
{
_pollInput = pollInput;
}
// Inherited via IKeyManager
virtual void RefreshState() override
{
if(_pollInput) {
_pollInput();
}
if(_getInputState) {
int32_t x = _getInputState(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
int32_t y = _getInputState(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
x += 0x8000;
y += 0x8000;
KeyManager::SetMousePosition(_console, (double)x / 0x10000, (double)y / 0x10000);
int16_t dx = _getInputState(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X);
int16_t dy = _getInputState(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y);
KeyManager::SetMouseMovement(dx, dy);
_mouseButtons[(int)MouseButton::LeftButton] = _getInputState(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT) != 0;
_mouseButtons[(int)MouseButton::RightButton] = _getInputState(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT) != 0;
_mouseButtons[(int)MouseButton::MiddleButton] = _getInputState(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_MIDDLE) != 0;
}
}
virtual bool IsKeyPressed(uint32_t keyCode) override
{
if(keyCode > 0 && _getInputState) {
return _getInputState(keyCode >> 8, RETRO_DEVICE_JOYPAD, 0, (keyCode - 1) & 0xFF) != 0;
} else {
return false;
}
}
virtual void UpdateDevices() override
{
}
virtual bool IsMouseButtonPressed(MouseButton button) override
{
return _mouseButtons[(int)button];
}
virtual vector<uint32_t> GetPressedKeys() override
{
return vector<uint32_t>();
}
virtual string GetKeyName(uint32_t keyCode) override
{
return string();
}
virtual uint32_t GetKeyCode(string keyName) override
{
return 0;
}
virtual void SetKeyState(uint16_t scanCode, bool state) override
{
}
virtual void ResetKeyState() override
{
}
virtual void SetDisabled(bool disabled) override
{
}
};

View File

@ -0,0 +1,38 @@
#pragma once
#include "libretro.h"
#include "../Core/IMessageManager.h"
#include "../Core/MessageManager.h"
class LibretroMessageManager : public IMessageManager
{
private:
retro_log_printf_t _log = nullptr;
retro_environment_t _retroEnv = nullptr;
public:
LibretroMessageManager(retro_log_printf_t logCallback, retro_environment_t retroEnv)
{
_log = logCallback;
_retroEnv = retroEnv;
MessageManager::RegisterMessageManager(this);
}
virtual ~LibretroMessageManager()
{
MessageManager::RegisterMessageManager(nullptr);
}
// Inherited via IMessageManager
virtual void DisplayMessage(string title, string message) override
{
if(title.empty()) {
if(_log) {
_log(RETRO_LOG_INFO, message.c_str());
}
} else {
string osdMessage = "[" + title + "] " + message;
retro_message msg = { osdMessage.c_str(), 180 };
_retroEnv(RETRO_ENVIRONMENT_SET_MESSAGE, &msg);
}
}
};

104
Libretro/LibretroRenderer.h Normal file
View File

@ -0,0 +1,104 @@
#pragma once
#include "../Core/IRenderingDevice.h"
#include "../Core/VideoRenderer.h"
#include "../Core/EmuSettings.h"
#include "../Core/Console.h"
#include "../Utilities/snes_ntsc.h"
#include "libretro.h"
class LibretroRenderer : public IRenderingDevice
{
private:
shared_ptr<Console> _console;
retro_video_refresh_t _sendFrame = nullptr;
retro_environment_t _retroEnv = nullptr;
bool _skipMode = false;
int32_t _previousHeight = -1;
int32_t _previousWidth = -1;
public:
LibretroRenderer(shared_ptr<Console> console, retro_environment_t retroEnv)
{
_console = console;
_retroEnv = retroEnv;
_console->GetVideoRenderer()->RegisterRenderingDevice(this);
}
~LibretroRenderer()
{
_console->GetVideoRenderer()->UnregisterRenderingDevice(this);
}
// Inherited via IRenderingDevice
virtual void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height) override
{
if(!_skipMode && _sendFrame) {
//Use Blargg's NTSC filter's max size as a minimum resolution, to prevent changing resolution too often
int32_t newWidth = std::max<int32_t>(width, SNES_NTSC_OUT_WIDTH(256));
int32_t newHeight = std::max<int32_t>(height, 240);
if(_retroEnv != nullptr && (_previousWidth != newWidth || _previousHeight != newHeight)) {
//Resolution change is needed
retro_system_av_info avInfo = {};
GetSystemAudioVideoInfo(avInfo, newWidth, newHeight);
_retroEnv(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &avInfo);
_previousWidth = newWidth;
_previousHeight = newHeight;
}
_sendFrame(frameBuffer, width, height, sizeof(uint32_t) * width);
}
}
void GetSystemAudioVideoInfo(retro_system_av_info &info, int32_t maxWidth = 0, int32_t maxHeight = 0)
{
AudioConfig audio = _console->GetSettings()->GetAudioConfig();
EmulationConfig emulation = _console->GetSettings()->GetEmulationConfig();
info.timing.fps = emulation.Region == ConsoleRegion::Ntsc ? 60.098811862348404716732985230828 : 50.006977968268290848936010226333;
info.timing.sample_rate = audio.SampleRate;
float ratio = (float)_console->GetSettings()->GetAspectRatio(_console->GetRegion());
if(ratio == 0.0f) {
ratio = (float)256 / 239;
}
OverscanDimensions overscan = _console->GetSettings()->GetOverscan();
int width = (256 - overscan.Left - overscan.Right) * 2;
int height = (239 - overscan.Top - overscan.Bottom) * 2;
ratio *= (float)width / height / 256 * 239;
info.geometry.aspect_ratio = ratio;
info.geometry.base_width = width;
info.geometry.base_height = height;
info.geometry.max_width = maxWidth;
info.geometry.max_height = maxHeight;
if(maxHeight > 0 && maxWidth > 0) {
_previousWidth = maxWidth;
_previousHeight = maxHeight;
}
}
void SetVideoCallback(retro_video_refresh_t sendFrame)
{
_sendFrame = sendFrame;
}
void SetSkipMode(bool skip)
{
_skipMode = skip;
}
virtual void Render() override
{
}
virtual void Reset() override
{
}
virtual void SetFullscreenMode(bool fullscreen, void *windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) override
{
}
};

View File

@ -0,0 +1,70 @@
#pragma once
#include "../Core/IAudioDevice.h"
#include "../Core/SoundMixer.h"
#include "libretro.h"
class LibretroSoundManager : public IAudioDevice
{
private:
retro_audio_sample_t _sendAudioSample = nullptr;
bool _skipMode = false;
shared_ptr<Console> _console;
public:
LibretroSoundManager(shared_ptr<Console> console)
{
_console = console;
_console->GetSoundMixer()->RegisterAudioDevice(this);
}
~LibretroSoundManager()
{
_console->GetSoundMixer()->RegisterAudioDevice(nullptr);
}
// Inherited via IAudioDevice
virtual void PlayBuffer(int16_t *soundBuffer, uint32_t sampleCount, uint32_t sampleRate, bool isStereo) override
{
if(!_skipMode && _sendAudioSample) {
for(uint32_t i = 0; i < sampleCount; i++) {
_sendAudioSample(soundBuffer[i*2], soundBuffer[i*2+1]);
}
}
}
void SetSendAudioSample(retro_audio_sample_t sendAudioSample)
{
_sendAudioSample = sendAudioSample;
}
void SetSkipMode(bool skip)
{
_skipMode = skip;
}
virtual void Stop() override
{
}
virtual void Pause() override
{
}
virtual string GetAvailableDevices() override
{
return string();
}
virtual void SetAudioDevice(string deviceName) override
{
}
virtual void ProcessEndOfFrame() override
{
}
virtual AudioStatistics GetStatistics() override
{
return AudioStatistics();
}
};

323
Libretro/Makefile Normal file
View File

@ -0,0 +1,323 @@
STATIC_LINKING := 0
AR := ar
SPACE :=
SPACE := $(SPACE) $(SPACE)
BACKSLASH :=
BACKSLASH := \$(BACKSLASH)
filter_out1 = $(filter-out $(firstword $1),$1)
filter_out2 = $(call filter_out1,$(call filter_out1,$1))
ifeq ($(platform),)
platform = unix
ifeq ($(shell uname -a),)
platform = win
else ifneq ($(findstring MINGW,$(shell uname -a)),)
platform = win
else ifneq ($(findstring Darwin,$(shell uname -a)),)
platform = osx
else ifneq ($(findstring win,$(shell uname -a)),)
platform = win
endif
endif
# system platform
system_platform = unix
ifeq ($(shell uname -a),)
EXE_EXT = .exe
system_platform = win
else ifneq ($(findstring Darwin,$(shell uname -a)),)
system_platform = osx
arch = intel
ifeq ($(shell uname -p),powerpc)
arch = ppc
endif
else ifneq ($(findstring MINGW,$(shell uname -a)),)
system_platform = win
endif
LIBRETRO_DIR += .
SEVENZIP_DIR += ../SevenZip
CORE_DIR += ../Core
UTIL_DIR += ../Utilities
TARGET_NAME := mesen-s
LIBM = -lm
ifeq ($(ARCHFLAGS),)
ifeq ($(archs),ppc)
ARCHFLAGS = -arch ppc -arch ppc64
else
ARCHFLAGS = -arch i386 -arch x86_64
endif
endif
ifeq ($(platform), osx)
ifndef ($(NOUNIVERSAL))
CXXFLAGS += $(ARCHFLAGS)
LFLAGS += $(ARCHFLAGS)
endif
endif
ifeq ($(STATIC_LINKING), 1)
EXT := a
endif
ifeq ($(platform), unix)
EXT ?= so
TARGET := $(TARGET_NAME)_libretro.$(EXT)
fpic := -fPIC -pthread
SHARED := -shared -Wl,--version-script=$(LIBRETRO_DIR)/link.T -Wl,--no-undefined
else ifeq ($(platform), linux-portable)
TARGET := $(TARGET_NAME)_libretro.$(EXT)
fpic := -fPIC -nostdlib
SHARED := -shared -Wl,--version-script=$(LIBRETRO_DIR)/link.T
LIBM :=
# Classic Platforms ####################
# Platform affix = classic_<ISA>_<µARCH>
# Help at https://modmyclassic.com/comp
# (armv7 a7, hard point, neon based) ###
# NESC, SNESC, C64 mini
else ifeq ($(platform), classic_armv7_a7)
TARGET := $(TARGET_NAME)_libretro.so
fpic := -fPIC -pthread
SHARED := -shared -Wl,--version-script=$(LIBRETRO_DIR)/link.T -Wl,--no-undefined
CFLAGS += -Ofast \
-flto=4 -fwhole-program -fuse-linker-plugin \
-fdata-sections -ffunction-sections -Wl,--gc-sections \
-fno-stack-protector -fno-ident -fomit-frame-pointer \
-falign-functions=1 -falign-jumps=1 -falign-loops=1 \
-fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops \
-fmerge-all-constants -fno-math-errno \
-marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard
CXXFLAGS += $(CFLAGS)
CPPFLAGS += $(CFLAGS)
ASFLAGS += $(CFLAGS)
HAVE_NEON = 1
ARCH = arm
BUILTIN_GPU = neon
USE_DYNAREC = 1
ifeq ($(shell echo `$(CC) -dumpversion` "< 4.9" | bc -l), 1)
CFLAGS += -march=armv7-a
else
CFLAGS += -march=armv7ve
# If gcc is 5.0 or later
ifeq ($(shell echo `$(CC) -dumpversion` ">= 5" | bc -l), 1)
LDFLAGS += -static-libgcc -static-libstdc++
endif
endif
#######################################
else ifneq (,$(findstring osx,$(platform)))
TARGET := $(TARGET_NAME)_libretro.dylib
fpic := -fPIC
SHARED := -dynamiclib
else ifneq (,$(findstring ios,$(platform)))
TARGET := $(TARGET_NAME)_libretro_ios.dylib
fpic := -fPIC
SHARED := -dynamiclib
ifeq ($(IOSSDK),)
IOSSDK := $(shell xcodebuild -version -sdk iphoneos Path)
endif
DEFINES := -DIOS
CC = cc -arch armv7 -isysroot $(IOSSDK)
ifeq ($(platform),ios9)
CC += -miphoneos-version-min=8.0
CXXFLAGS += -miphoneos-version-min=8.0
else
CC += -miphoneos-version-min=5.0
CXXFLAGS += -miphoneos-version-min=5.0
endif
else ifneq (,$(findstring qnx,$(platform)))
TARGET := $(TARGET_NAME)_libretro_qnx.so
fpic := -fPIC
SHARED := -shared -Wl,--version-script=$(LIBRETRO_DIR)/link.T -Wl,--no-undefined
else ifeq ($(platform), emscripten)
TARGET := $(TARGET_NAME)_libretro_emscripten.bc
fpic := -fPIC
SHARED := -shared -Wl,--version-script=$(LIBRETRO_DIR)/link.T -Wl,--no-undefined
else ifeq ($(platform), vita)
TARGET := $(TARGET_NAME)_vita.a
CC = arm-vita-eabi-gcc
AR = arm-vita-eabi-ar
CXXFLAGS += -Wl,-q -Wall -O3
STATIC_LINKING = 1
# Windows MSVC 2017 all architectures
else ifneq (,$(findstring windows_msvc2017,$(platform)))
PlatformSuffix = $(subst windows_msvc2017_,,$(platform))
ifneq (,$(findstring desktop,$(PlatformSuffix)))
WinPartition = desktop
MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -FS -MP -GL -W0 -Gy -Zc:wchar_t -Gm- -Ox -Ob2 -sdl- -Zc:inline -fp:precise -DLIBRETRO -DWIN32 -D_CONSOLE -D_LIB -D_UNICODE -DUNICODE -errorReport:prompt -WX- -Zc:forScope -Gd -Oy -Oi -MT -EHsc -Ot -diagnostics:classic
LDFLAGS += -MANIFEST -LTCG:incremental -NXCOMPAT -DYNAMICBASE -OPT:REF -INCREMENTAL:NO -SUBSYSTEM:WINDOWS -MANIFESTUAC:"level='asInvoker' uiAccess='false'" -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1
LIBS += kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib
else ifneq (,$(findstring uwp,$(PlatformSuffix)))
WinPartition = uwp
MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_APP -DWINDLL -D_UNICODE -DUNICODE -DWRL_NO_DEFAULT_LIB -FS
LDFLAGS += -APPCONTAINER -NXCOMPAT -DYNAMICBASE -MANIFEST:NO -LTCG -OPT:REF -SUBSYSTEM:CONSOLE -MANIFESTUAC:NO -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 -DEBUG:FULL -WINMD:NO
LIBS += WindowsApp.lib
endif
CFLAGS += $(MSVC2017CompileFlags)
CXXFLAGS += $(MSVC2017CompileFlags)
TargetArchMoniker = $(subst $(WinPartition)_,,$(PlatformSuffix))
CC = cl.exe
CXX = cl.exe
reg_query = $(call filter_out2,$(subst $2,,$(shell reg query "$2" -v "$1" 2>nul)))
fix_path = $(subst $(SPACE),\ ,$(subst \,/,$1))
ProgramFiles86w := $(shell cmd /c "echo %PROGRAMFILES(x86)%")
ProgramFiles86 := $(shell cygpath "$(ProgramFiles86w)")
WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0)
WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0)
WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0)
WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0)
WindowsSdkDir := $(WindowsSdkDir)
WindowsSDKVersion ?= $(firstword $(foreach folder,$(subst $(subst \,/,$(WindowsSdkDir)Include/),,$(wildcard $(call fix_path,$(WindowsSdkDir)Include\*))),$(if $(wildcard $(call fix_path,$(WindowsSdkDir)Include/$(folder)/um/Windows.h)),$(folder),)))$(BACKSLASH)
WindowsSDKVersion := $(WindowsSDKVersion)
VsInstallBuildTools = $(ProgramFiles86)/Microsoft Visual Studio/2017/BuildTools
VsInstallEnterprise = $(ProgramFiles86)/Microsoft Visual Studio/2017/Enterprise
VsInstallProfessional = $(ProgramFiles86)/Microsoft Visual Studio/2017/Professional
VsInstallCommunity = $(ProgramFiles86)/Microsoft Visual Studio/2017/Community
VsInstallRoot ?= $(shell if [ -d "$(VsInstallBuildTools)" ]; then echo "$(VsInstallBuildTools)"; fi)
ifeq ($(VsInstallRoot), )
VsInstallRoot = $(shell if [ -d "$(VsInstallEnterprise)" ]; then echo "$(VsInstallEnterprise)"; fi)
endif
ifeq ($(VsInstallRoot), )
VsInstallRoot = $(shell if [ -d "$(VsInstallProfessional)" ]; then echo "$(VsInstallProfessional)"; fi)
endif
ifeq ($(VsInstallRoot), )
VsInstallRoot = $(shell if [ -d "$(VsInstallCommunity)" ]; then echo "$(VsInstallCommunity)"; fi)
endif
VsInstallRoot := $(VsInstallRoot)
VcCompilerToolsVer := $(shell cat "$(VsInstallRoot)/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt" | grep -o '[0-9\.]*')
VcCompilerToolsDir := $(VsInstallRoot)/VC/Tools/MSVC/$(VcCompilerToolsVer)
WindowsSDKSharedIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\shared")
WindowsSDKUCRTIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\ucrt")
WindowsSDKUMIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\um")
WindowsSDKUCRTLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\ucrt\$(TargetArchMoniker)")
WindowsSDKUMLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\um\$(TargetArchMoniker)")
# For some reason the HostX86 compiler doesn't like compiling for x64
# ("no such file" opening a shared library), and vice-versa.
# Work around it for now by using the strictly x86 compiler for x86, and x64 for x64.
# NOTE: What about ARM?
ifneq (,$(findstring x64,$(TargetArchMoniker)))
VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX64
else
VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX86
endif
PATH := $(shell IFS=$$'\n'; cygpath "$(VCCompilerToolsBinDir)/$(TargetArchMoniker)"):$(PATH)
PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VsInstallRoot)/Common7/IDE")
INCLUDE := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/include")
LIB := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/lib/$(TargetArchMoniker)")
export INCLUDE := $(INCLUDE);$(WindowsSDKSharedIncludeDir);$(WindowsSDKUCRTIncludeDir);$(WindowsSDKUMIncludeDir)
export LIB := $(LIB);$(WindowsSDKUCRTLibDir);$(WindowsSDKUMLibDir)
TARGET := $(TARGET_NAME)_libretro.dll
PSS_STYLE :=2
LDFLAGS += -DLL
LIBM :=
else
CC = gcc
CXX = g++
TARGET := $(TARGET_NAME)_libretro.dll
SHARED := -shared -s -Wl,--version-script=$(LIBRETRO_DIR)/link.T -Wl,--no-undefined
endif
LDFLAGS += $(LIBM)
ifeq ($(LTO),true)
CFLAGS += -flto
CXXFLAGS += -flto
LD = g++
endif
ifeq ($(DEBUG), 1)
ifneq (,$(findstring msvc,$(platform)))
CFLAGS += -MTd -Od -Zi -DDEBUG -D_DEBUG
CXXFLAGS += -MTd -Od -Zi -DDEBUG -D_DEBUG
else
CFLAGS += -O0 -g
CXXFLAGS += -O0 -g
endif
else
ifneq (,$(findstring msvc,$(platform)))
CFLAGS += -MT -O2 -DNDEBUG
CXXFLAGS += -MT -O2 -DNDEBUG
else
CFLAGS += -O3
CXXFLAGS += -O3
endif
endif
ifneq (,$(findstring msvc,$(platform)))
OBJOUT = -Fo
LINKOUT = -out:
ifeq ($(STATIC_LINKING),1)
LD ?= lib.exe
STATIC_LINKING=0
else
LD = link.exe
endif
else
OBJOUT = -o
LINKOUT = -o
LD = $(CXX)
endif
include Makefile.common
OBJECTS := $(SOURCES_C:.c=.o) $(SOURCES_CXX:.cpp=.o)
ifeq (,$(findstring windows_msvc2017,$(platform)))
CFLAGS += -Wall
CXXFLAGS += -Wall
endif
CFLAGS += -D LIBRETRO $(fpic)
CXXFLAGS += -D LIBRETRO $(fpic) -std=c++14
all: $(TARGET)
$(TARGET): $(OBJECTS)
@echo "** BUILDING $(TARGET) FOR PLATFORM $(platform) **"
ifeq ($(STATIC_LINKING), 1)
ifneq (,$(findstring msvc,$(platform)))
$(LD) $(LINKOUT)$@ $(OBJECTS)
else
$(AR) rcs $@ $(OBJECTS)
endif
else
$(LD) $(fpic) $(SHARED) $(INCLUDES) $(LINKOUT)$@ $(OBJECTS) $(LDFLAGS)
endif
@echo "** BUILD SUCCESSFUL! GG NO RE **"
%.o: %.c
$(CC) $(CFLAGS) $(fpic) -c $< $(OBJOUT)$@
%.o: %.cpp
$(CXX) $(CXXFLAGS) $(fpic) -c $< $(OBJOUT)$@
clean:
rm -f $(OBJECTS) $(TARGET)
.PHONY: clean
print-%:
@echo '$*=$($*)'

121
Libretro/Makefile.common Normal file
View File

@ -0,0 +1,121 @@
SOURCES_C := $(SEVENZIP_DIR)/7zAlloc.c \
$(SEVENZIP_DIR)/7zArcIn.c \
$(SEVENZIP_DIR)/7zBuf.c \
$(SEVENZIP_DIR)/7zCrc.c \
$(SEVENZIP_DIR)/7zCrcOpt.c \
$(SEVENZIP_DIR)/7zDec.c \
$(SEVENZIP_DIR)/7zFile.c \
$(SEVENZIP_DIR)/7zMemBuffer.c \
$(SEVENZIP_DIR)/7zStream.c \
$(SEVENZIP_DIR)/Bcj2.c \
$(SEVENZIP_DIR)/Bra.c \
$(SEVENZIP_DIR)/Bra86.c \
$(SEVENZIP_DIR)/BraIA64.c \
$(SEVENZIP_DIR)/CpuArch.c \
$(SEVENZIP_DIR)/Delta.c \
$(SEVENZIP_DIR)/Lzma2Dec.c \
$(SEVENZIP_DIR)/LzmaDec.c \
$(SEVENZIP_DIR)/Ppmd7.c \
$(SEVENZIP_DIR)/Ppmd7Dec.c \
$(SEVENZIP_DIR)/Precomp.c \
SOURCES_CXX := $(LIBRETRO_DIR)/libretro.cpp \
$(CORE_DIR)/AviRecorder.cpp \
$(CORE_DIR)/BaseCartridge.cpp \
$(CORE_DIR)/BaseControlDevice.cpp \
$(CORE_DIR)/BaseRenderer.cpp \
$(CORE_DIR)/BaseSoundManager.cpp \
$(CORE_DIR)/BaseVideoFilter.cpp \
$(CORE_DIR)/Breakpoint.cpp \
$(CORE_DIR)/BreakpointManager.cpp \
$(CORE_DIR)/CallstackManager.cpp \
$(CORE_DIR)/CodeDataLogger.cpp \
$(CORE_DIR)/Console.cpp \
$(CORE_DIR)/ConsoleLock.cpp \
$(CORE_DIR)/ControlManager.cpp \
$(CORE_DIR)/Cpu.cpp \
$(CORE_DIR)/Cpu.Instructions.cpp \
$(CORE_DIR)/CpuDisUtils.cpp \
$(CORE_DIR)/Debugger.cpp \
$(CORE_DIR)/DebugHud.cpp \
$(CORE_DIR)/DebugStats.cpp \
$(CORE_DIR)/DefaultVideoFilter.cpp \
$(CORE_DIR)/Disassembler.cpp \
$(CORE_DIR)/DisassemblyInfo.cpp \
$(CORE_DIR)/DmaController.cpp \
$(CORE_DIR)/EmuSettings.cpp \
$(CORE_DIR)/EventManager.cpp \
$(CORE_DIR)/ExpressionEvaluator.cpp \
$(CORE_DIR)/InternalRegisters.cpp \
$(CORE_DIR)/KeyManager.cpp \
$(CORE_DIR)/LabelManager.cpp \
$(CORE_DIR)/MemoryAccessCounter.cpp \
$(CORE_DIR)/MemoryDumper.cpp \
$(CORE_DIR)/MemoryManager.cpp \
$(CORE_DIR)/MessageManager.cpp \
$(CORE_DIR)/NotificationManager.cpp \
$(CORE_DIR)/NtscFilter.cpp \
$(CORE_DIR)/Ppu.cpp \
$(CORE_DIR)/PpuTools.cpp \
$(CORE_DIR)/RegisterHandlerB.cpp \
$(CORE_DIR)/RewindData.cpp \
$(CORE_DIR)/RewindManager.cpp \
$(CORE_DIR)/SaveStateManager.cpp \
$(CORE_DIR)/ScaleFilter.cpp \
$(CORE_DIR)/ScriptHost.cpp \
$(CORE_DIR)/ScriptingContext.cpp \
$(CORE_DIR)/ScriptManager.cpp \
$(CORE_DIR)/ShortcutKeyHandler.cpp \
$(CORE_DIR)/SoundMixer.cpp \
$(CORE_DIR)/SoundResampler.cpp \
$(CORE_DIR)/Spc.cpp \
$(CORE_DIR)/Spc.Instructions.cpp \
$(CORE_DIR)/SpcDisUtils.cpp \
$(CORE_DIR)/SPC_DSP.cpp \
$(CORE_DIR)/SPC_Filter.cpp \
$(CORE_DIR)/stdafx.cpp \
$(CORE_DIR)/TraceLogger.cpp \
$(CORE_DIR)/VideoDecoder.cpp \
$(CORE_DIR)/VideoRenderer.cpp \
$(CORE_DIR)/WaveRecorder.cpp \
$(UTIL_DIR)/ArchiveReader.cpp \
$(UTIL_DIR)/AutoResetEvent.cpp \
$(UTIL_DIR)/AviWriter.cpp \
$(UTIL_DIR)/blip_buf.cpp \
$(UTIL_DIR)/BpsPatcher.cpp \
$(UTIL_DIR)/CamstudioCodec.cpp \
$(UTIL_DIR)/CRC32.cpp \
$(UTIL_DIR)/Equalizer.cpp \
$(UTIL_DIR)/FolderUtilities.cpp \
$(UTIL_DIR)/HexUtilities.cpp \
$(UTIL_DIR)/IpsPatcher.cpp \
$(UTIL_DIR)/md5.cpp \
$(UTIL_DIR)/miniz.cpp \
$(UTIL_DIR)/snes_ntsc.cpp \
$(UTIL_DIR)/PlatformUtilities.cpp \
$(UTIL_DIR)/PNGHelper.cpp \
$(UTIL_DIR)/Serializer.cpp \
$(UTIL_DIR)/sha1.cpp \
$(UTIL_DIR)/SimpleLock.cpp \
$(UTIL_DIR)/Socket.cpp \
$(UTIL_DIR)/stb_vorbis.cpp \
$(UTIL_DIR)/stdafx.cpp \
$(UTIL_DIR)/SZReader.cpp \
$(UTIL_DIR)/Timer.cpp \
$(UTIL_DIR)/UpsPatcher.cpp \
$(UTIL_DIR)/UTF8Util.cpp \
$(UTIL_DIR)/VirtualFile.cpp \
$(UTIL_DIR)/ZipReader.cpp \
$(UTIL_DIR)/ZipWriter.cpp \
$(UTIL_DIR)/ZmbvCodec.cpp \
$(UTIL_DIR)/HQX/hq2x.cpp \
$(UTIL_DIR)/HQX/hq3x.cpp \
$(UTIL_DIR)/HQX/hq4x.cpp \
$(UTIL_DIR)/HQX/init.cpp \
$(UTIL_DIR)/KreedSaiEagle/2xSai.cpp \
$(UTIL_DIR)/KreedSaiEagle/Super2xSai.cpp \
$(UTIL_DIR)/KreedSaiEagle/SuperEagle.cpp \
$(UTIL_DIR)/Scale2x/scale2x.cpp \
$(UTIL_DIR)/Scale2x/scale3x.cpp \
$(UTIL_DIR)/Scale2x/scalebit.cpp \
$(UTIL_DIR)/xBRZ/xbrz.cpp \

27
Libretro/jni/Android.mk Normal file
View File

@ -0,0 +1,27 @@
LOCAL_PATH := $(call my-dir)
ROOT_DIR := $(LOCAL_PATH)/../..
CORE_DIR := $(ROOT_DIR)/Core
LIBRETRO_DIR := $(ROOT_DIR)/Libretro
SEVENZIP_DIR := $(ROOT_DIR)/SevenZip
UTIL_DIR := $(ROOT_DIR)/Utilities
HAVE_NETWORK := 1
include $(LIBRETRO_DIR)/Makefile.common
COREFLAGS := -DLIBRETRO
GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)"
ifneq ($(GIT_VERSION)," unknown")
COREFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\"
endif
include $(CLEAR_VARS)
LOCAL_MODULE := retro
LOCAL_SRC_FILES := $(SOURCES_CXX) $(SOURCES_C)
LOCAL_CFLAGS := $(COREFLAGS)
LOCAL_CXXFLAGS := $(COREFLAGS) -std=c++11
LOCAL_LDFLAGS := -Wl,-version-script=$(LIBRETRO_DIR)/link.T
LOCAL_CPP_FEATURES := exceptions rtti
include $(BUILD_SHARED_LIBRARY)

View File

@ -0,0 +1,7 @@
APP_STL:=c++_static
APP_ABI := all
# Don't strip debug builds
ifeq ($(NDK_DEBUG),1)
cmd-strip :=
endif

558
Libretro/libretro.cpp Normal file
View File

@ -0,0 +1,558 @@
#include <string>
#include <sstream>
#include <algorithm>
#include "LibretroRenderer.h"
#include "LibretroSoundManager.h"
#include "LibretroKeyManager.h"
#include "LibretroMessageManager.h"
#include "libretro.h"
#include "../Core/Console.h"
#include "../Core/BaseCartridge.h"
#include "../Core/MemoryManager.h"
#include "../Core/VideoDecoder.h"
#include "../Core/VideoRenderer.h"
#include "../Core/EmuSettings.h"
#include "../Core/SaveStateManager.h"
#include "../Utilities/snes_ntsc.h"
#include "../Utilities/FolderUtilities.h"
#include "../Utilities/HexUtilities.h"
#define DEVICE_AUTO RETRO_DEVICE_JOYPAD
#define DEVICE_GAMEPAD RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0)
#define DEVICE_SNESMOUSE RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 2)
static retro_log_printf_t logCallback = nullptr;
static retro_environment_t retroEnv = nullptr;
static unsigned _inputDevices[5] = { DEVICE_GAMEPAD, DEVICE_GAMEPAD, DEVICE_AUTO, DEVICE_AUTO, DEVICE_AUTO };
static string _mesenVersion = "";
static int32_t _saveStateSize = -1;
static std::shared_ptr<Console> _console;
static std::unique_ptr<LibretroRenderer> _renderer;
static std::unique_ptr<LibretroSoundManager> _soundManager;
static std::unique_ptr<LibretroKeyManager> _keyManager;
static std::unique_ptr<LibretroMessageManager> _messageManager;
static const char* MesenNtscFilter = "mesen_ntsc_filter";
static const char* MesenRegion = "mesen_region";
static const char* MesenAspectRatio = "mesen_aspect_ratio";
static const char* MesenOverscanVertical = "mesen_overscan_vertical";
static const char* MesenOverscanHorizontal = "mesen_overscan_horizontal";
extern "C" {
void logMessage(retro_log_level level, const char* message)
{
if(logCallback) {
logCallback(level, message);
}
}
RETRO_API unsigned retro_api_version()
{
return RETRO_API_VERSION;
}
RETRO_API void retro_init()
{
struct retro_log_callback log;
if(retroEnv(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) {
logCallback = log.log;
} else {
logCallback = nullptr;
}
_console.reset(new Console());
_console->Initialize();
_renderer.reset(new LibretroRenderer(_console, retroEnv));
_soundManager.reset(new LibretroSoundManager(_console));
_keyManager.reset(new LibretroKeyManager(_console));
_messageManager.reset(new LibretroMessageManager(logCallback, retroEnv));
AudioConfig audioConfig = _console->GetSettings()->GetAudioConfig();
audioConfig.SampleRate = 32000;
_console->GetSettings()->SetAudioConfig(audioConfig);
PreferencesConfig preferences = _console->GetSettings()->GetPreferences();
preferences.RewindBufferSize = 0;
_console->GetSettings()->SetPreferences(preferences);
}
RETRO_API void retro_deinit()
{
_renderer.reset();
_soundManager.reset();
_keyManager.reset();
_messageManager.reset();
//_console->SaveBatteries();
_console->Release();
_console.reset();
}
RETRO_API void retro_set_environment(retro_environment_t env)
{
retroEnv = env;
static const struct retro_variable vars[] = {
{ MesenNtscFilter, "NTSC filter; Disabled|Composite (Blargg)|S-Video (Blargg)|RGB (Blargg)|Monochrome (Blargg)" },
{ MesenRegion, "Region; Auto|NTSC|PAL" },
{ MesenOverscanVertical, "Vertical Overscan; None|8px|16px" },
{ MesenOverscanHorizontal, "Horizontal Overscan; None|8px|16px" },
{ MesenAspectRatio, "Aspect Ratio; Auto|No Stretching|NTSC|PAL|4:3|16:9" },
{ NULL, NULL },
};
static const struct retro_controller_description pads1[] = {
//{ "Auto", DEVICE_AUTO },
{ "SNES Controller", DEVICE_GAMEPAD },
{ "SNES Mouse", DEVICE_SNESMOUSE },
{ NULL, 0 },
};
static const struct retro_controller_description pads2[] = {
//{ "Auto", DEVICE_AUTO },
{ "SNES Controller", DEVICE_GAMEPAD },
{ "SNES Mouse", DEVICE_SNESMOUSE },
{ NULL, 0 },
};
static const struct retro_controller_info ports[] = {
{ pads1, 2 },
{ pads2, 2 },
{ 0 },
};
retroEnv(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars);
retroEnv(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports);
}
RETRO_API void retro_set_video_refresh(retro_video_refresh_t sendFrame)
{
_renderer->SetVideoCallback(sendFrame);
}
RETRO_API void retro_set_audio_sample(retro_audio_sample_t sendAudioSample)
{
_soundManager->SetSendAudioSample(sendAudioSample);
}
RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t audioSampleBatch)
{
}
RETRO_API void retro_set_input_poll(retro_input_poll_t pollInput)
{
_keyManager->SetPollInput(pollInput);
}
RETRO_API void retro_set_input_state(retro_input_state_t getInputState)
{
_keyManager->SetGetInputState(getInputState);
}
RETRO_API void retro_reset()
{
_console->Reset();
}
bool readVariable(const char* key, retro_variable &var)
{
var.key = key;
var.value = nullptr;
if(retroEnv(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value != nullptr) {
return true;
}
return false;
}
void update_settings()
{
struct retro_variable var = { };
VideoConfig video = _console->GetSettings()->GetVideoConfig();
EmulationConfig emulation = _console->GetSettings()->GetEmulationConfig();
InputConfig input = _console->GetSettings()->GetInputConfig();
video.Brightness = 0;
video.Contrast = 0;
video.Hue = 0;
video.Saturation = 0;
video.ScanlineIntensity = 0;
if(readVariable(MesenNtscFilter, var)) {
string value = string(var.value);
if(value == "Disabled") {
video.VideoFilter = VideoFilterType::None;
} else if(value == "Composite (Blargg)") {
video.VideoFilter = VideoFilterType::NTSC;
video.NtscArtifacts = 0;
video.NtscBleed = 0;
video.NtscFringing = 0;
video.NtscGamma = 0;
video.NtscResolution = 0;
video.NtscSharpness = 0;
video.NtscMergeFields = false;
} else if(value == "S-Video (Blargg)") {
video.VideoFilter = VideoFilterType::NTSC;
video.NtscArtifacts = -1.0;
video.NtscBleed = 0;
video.NtscFringing = -1.0;
video.NtscGamma = 0;
video.NtscResolution = 0.2;
video.NtscSharpness = 0.2;
video.NtscMergeFields = false;
} else if(value == "RGB (Blargg)") {
video.VideoFilter = VideoFilterType::NTSC;
video.NtscArtifacts = -1.0;
video.NtscBleed = -1.0;
video.NtscFringing = -1.0;
video.NtscGamma = 0;
video.NtscResolution = 0.7;
video.NtscSharpness = 0.2;
video.NtscMergeFields = false;
} else if(value == "Monochrome (Blargg)") {
video.VideoFilter = VideoFilterType::NTSC;
video.Saturation = -1.0;
video.NtscArtifacts = -0.2;
video.NtscBleed = -1.0;
video.NtscFringing = -0.2;
video.NtscGamma = 0;
video.NtscResolution = 0.2;
video.NtscSharpness = 0.2;
video.NtscMergeFields = false;
}
}
int overscanHorizontal = 0;
int overscanVertical = 0;
if(readVariable(MesenOverscanHorizontal, var)) {
string value = string(var.value);
if(value == "8px") {
overscanHorizontal = 8;
} else if(value == "16px") {
overscanHorizontal = 16;
}
}
if(readVariable(MesenOverscanVertical, var)) {
string value = string(var.value);
if(value == "8px") {
overscanVertical = 8;
} else if(value == "16px") {
overscanVertical = 16;
}
}
video.OverscanLeft = overscanHorizontal;
video.OverscanRight = overscanHorizontal;
video.OverscanTop = overscanVertical;
video.OverscanBottom = overscanVertical;
if(readVariable(MesenAspectRatio, var)) {
string value = string(var.value);
if(value == "Auto") {
video.AspectRatio = VideoAspectRatio::Auto;
} else if(value == "No Stretching") {
video.AspectRatio = VideoAspectRatio::NoStretching;
} else if(value == "NTSC") {
video.AspectRatio = VideoAspectRatio::NTSC;
} else if(value == "PAL") {
video.AspectRatio = VideoAspectRatio::PAL;
} else if(value == "4:3") {
video.AspectRatio = VideoAspectRatio::Standard;
} else if(value == "16:9") {
video.AspectRatio = VideoAspectRatio::Widescreen;
}
}
if(readVariable(MesenRegion, var)) {
string value = string(var.value);
if(value == "Auto") {
emulation.Region = ConsoleRegion::Auto;
} else if(value == "NTSC") {
emulation.Region = ConsoleRegion::Ntsc;
} else if(value == "PAL") {
emulation.Region = ConsoleRegion::Pal;
}
}
auto getKeyCode = [=](int port, int retroKey) {
return (port << 8) | (retroKey + 1);
};
auto getKeyBindings = [=](int port) {
KeyMappingSet keyMappings;
keyMappings.TurboSpeed = 0;
keyMappings.Mapping1.L = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_L);
keyMappings.Mapping1.R = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_R);
keyMappings.Mapping1.A = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_A);
keyMappings.Mapping1.B = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_B);
keyMappings.Mapping1.X = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_X);
keyMappings.Mapping1.Y = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_Y);
keyMappings.Mapping1.Start = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_START);
keyMappings.Mapping1.Select = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_SELECT);
keyMappings.Mapping1.Up = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_UP);
keyMappings.Mapping1.Down = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_DOWN);
keyMappings.Mapping1.Left = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_LEFT);
keyMappings.Mapping1.Right = getKeyCode(port, RETRO_DEVICE_ID_JOYPAD_RIGHT);
return keyMappings;
};
input.Controllers[0].Keys = getKeyBindings(0);
input.Controllers[1].Keys = getKeyBindings(1);
input.Controllers[2].Keys = getKeyBindings(2);
input.Controllers[3].Keys = getKeyBindings(3);
_console->GetSettings()->SetVideoConfig(video);
_console->GetSettings()->SetEmulationConfig(emulation);
_console->GetSettings()->SetInputConfig(input);
retro_system_av_info avInfo = {};
_renderer->GetSystemAudioVideoInfo(avInfo);
retroEnv(RETRO_ENVIRONMENT_SET_GEOMETRY, &avInfo);
}
RETRO_API void retro_run()
{
if(_console->GetSettings()->CheckFlag(EmulationFlags::MaximumSpeed)) {
//Skip frames to speed up emulation while still outputting at 50/60 fps (needed for FDS fast forward while loading)
_renderer->SetSkipMode(true);
_soundManager->SetSkipMode(true);
for(int i = 0; i < 9; i++) {
//Attempt to speed up to 1000% speed
_console->RunSingleFrame();
}
_renderer->SetSkipMode(false);
_soundManager->SetSkipMode(false);
}
bool updated = false;
if(retroEnv(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) {
update_settings();
}
_console->RunSingleFrame();
if(updated) {
//Update geometry after running the frame, in case the console's region changed (affects "auto" aspect ratio)
retro_system_av_info avInfo = {};
_renderer->GetSystemAudioVideoInfo(avInfo);
retroEnv(RETRO_ENVIRONMENT_SET_GEOMETRY, &avInfo);
}
}
RETRO_API size_t retro_serialize_size()
{
return _saveStateSize;
}
RETRO_API bool retro_serialize(void *data, size_t size)
{
std::stringstream ss;
_console->Serialize(ss);
string saveStateData = ss.str();
memset(data, 0, size);
memcpy(data, saveStateData.c_str(), std::min(size, saveStateData.size()));
return true;
}
RETRO_API bool retro_unserialize(const void *data, size_t size)
{
std::stringstream ss;
ss.write((const char*)data, size);
_console->Deserialize(ss, SaveStateManager::FileFormatVersion);
return true;
}
RETRO_API void retro_cheat_reset()
{
}
RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *codeStr)
{
}
void update_input_descriptors()
{
vector<retro_input_descriptor> desc;
auto addDesc = [&desc](unsigned port, unsigned button, const char* name) {
retro_input_descriptor d = { port, RETRO_DEVICE_JOYPAD, 0, button, name };
desc.push_back(d);
};
auto setupPlayerButtons = [addDesc](int port) {
unsigned device = _inputDevices[port];
if(device == DEVICE_AUTO) {
if(port <= 3) {
switch(_console->GetSettings()->GetInputConfig().Controllers[port].Type) {
case ControllerType::SnesController: device = DEVICE_GAMEPAD; break;
case ControllerType::SnesMouse: device = DEVICE_SNESMOUSE; break;
default: return;
}
}
}
if(device == DEVICE_GAMEPAD) {
addDesc(port, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left");
addDesc(port, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up");
addDesc(port, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down");
addDesc(port, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right");
addDesc(port, RETRO_DEVICE_ID_JOYPAD_A, "A");
addDesc(port, RETRO_DEVICE_ID_JOYPAD_B, "B");
addDesc(port, RETRO_DEVICE_ID_JOYPAD_X, "X");
addDesc(port, RETRO_DEVICE_ID_JOYPAD_Y, "Y");
addDesc(port, RETRO_DEVICE_ID_JOYPAD_L, "L");
addDesc(port, RETRO_DEVICE_ID_JOYPAD_R, "R");
}
};
setupPlayerButtons(0);
setupPlayerButtons(1);
retro_input_descriptor end = { 0 };
desc.push_back(end);
retroEnv(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc.data());
}
void update_core_controllers()
{
InputConfig input = _console->GetSettings()->GetInputConfig();
for(int port = 0; port < 2; port++) {
ControllerType type = ControllerType::SnesController;
switch(_inputDevices[port]) {
case RETRO_DEVICE_NONE: type = ControllerType::None; break;
case DEVICE_GAMEPAD: type = ControllerType::SnesController; break;
case DEVICE_SNESMOUSE: type = ControllerType::SnesMouse; break;
}
input.Controllers[port].Type = type;
}
_console->GetSettings()->SetInputConfig(input);
}
void retro_set_memory_maps()
{
}
RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device)
{
if(port < 2 && _inputDevices[port] != device) {
_inputDevices[port] = device;
update_core_controllers();
update_input_descriptors();
}
}
RETRO_API bool retro_load_game(const struct retro_game_info *game)
{
char *systemFolder;
if(!retroEnv(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &systemFolder) || !systemFolder) {
return false;
}
char *saveFolder;
if(!retroEnv(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &saveFolder)) {
logMessage(RETRO_LOG_ERROR, "Could not find save directory.\n");
}
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
if(!retroEnv(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) {
logMessage(RETRO_LOG_ERROR, "XRGB8888 is not supported.\n");
return false;
}
//Expect the following structure:
// /saves/*.sav
FolderUtilities::SetHomeFolder(systemFolder);
FolderUtilities::SetFolderOverrides(saveFolder, "", "");
update_settings();
//Plug in 2 standard controllers by default, game database will switch the controller types for recognized games
/*
_console->GetSettings()->SetControllerType(0, ControllerType::SnesController);
_console->GetSettings()->SetControllerType(1, ControllerType::SnesController);
_console->GetSettings()->SetControllerType(2, ControllerType::None);
_console->GetSettings()->SetControllerType(3, ControllerType::None);*/
VirtualFile romData(game->data, game->size, game->path);
VirtualFile patch;
bool result = _console->LoadRom(romData, patch);
if(result) {
update_core_controllers();
update_input_descriptors();
//Savestates in Mesen may change size over time
//Retroarch doesn't like this for netplay or rewinding - it requires the states to always be the exact same size
//So we need to send a large enough size to Retroarch to ensure Mesen's state will always fit within that buffer.
std::stringstream ss;
_console->Serialize(ss);
//Round up to the next 1kb multiple
_saveStateSize = ((ss.str().size() * 2) + 0x400) & ~0x3FF;
retro_set_memory_maps();
}
return result;
}
RETRO_API bool retro_load_game_special(unsigned game_type, const struct retro_game_info *info, size_t num_info)
{
return false;
}
RETRO_API void retro_unload_game()
{
_console->Stop(false);
}
RETRO_API unsigned retro_get_region()
{
ConsoleRegion region = _console->GetRegion();
return region == ConsoleRegion::Ntsc ? RETRO_REGION_NTSC : RETRO_REGION_PAL;
}
RETRO_API void retro_get_system_info(struct retro_system_info *info)
{
if(!_console) {
_console.reset(new Console());
_console->Initialize();
}
_mesenVersion = _console->GetSettings()->GetVersionString();
info->library_name = "Mesen-S";
info->library_version = _mesenVersion.c_str();
info->need_fullpath = false;
info->valid_extensions = "sfc|smc|fig|swc";
info->block_extract = false;
}
RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info)
{
_renderer->GetSystemAudioVideoInfo(*info, SNES_NTSC_OUT_WIDTH(256), 239 * 2);
}
RETRO_API void *retro_get_memory_data(unsigned id)
{
switch(id) {
case RETRO_MEMORY_SAVE_RAM: return _console->GetCartridge()->DebugGetSaveRam();
case RETRO_MEMORY_SYSTEM_RAM: return _console->GetMemoryManager()->DebugGetWorkRam();
}
return nullptr;
}
RETRO_API size_t retro_get_memory_size(unsigned id)
{
switch(id) {
case RETRO_MEMORY_SAVE_RAM: _console->GetCartridge()->DebugGetSaveRamSize(); break;
case RETRO_MEMORY_SYSTEM_RAM: return MemoryManager::WorkRamSize;
}
return 0;
}
}

2323
Libretro/libretro.h Normal file

File diff suppressed because it is too large Load Diff

5
Libretro/link.T Normal file
View File

@ -0,0 +1,5 @@
{
global: retro_*;
local: *;
};

View File

@ -50,6 +50,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SevenZip", "SevenZip\SevenZ
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Lua", "Lua\Lua.vcxproj", "{B609E0A0-5050-4871-91D6-E760633BCDD1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Libretro", "Libretro\Libretro.vcxproj", "{4432139E-528B-44DE-961C-B37CD5E92E0E}"
ProjectSection(ProjectDependencies) = postProject
{B5330148-E8C7-46BA-B54E-69BE59EA337D} = {B5330148-E8C7-46BA-B54E-69BE59EA337D}
{78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0} = {78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -304,7 +310,6 @@ Global
{B609E0A0-5050-4871-91D6-E760633BCDD1}.Debug|x86.Build.0 = Debug|Win32
{B609E0A0-5050-4871-91D6-E760633BCDD1}.Libretro|Any CPU.ActiveCfg = Libretro|Win32
{B609E0A0-5050-4871-91D6-E760633BCDD1}.Libretro|x64.ActiveCfg = Libretro|x64
{B609E0A0-5050-4871-91D6-E760633BCDD1}.Libretro|x64.Build.0 = Libretro|x64
{B609E0A0-5050-4871-91D6-E760633BCDD1}.Libretro|x86.ActiveCfg = Libretro|Win32
{B609E0A0-5050-4871-91D6-E760633BCDD1}.Libretro|x86.Build.0 = Libretro|Win32
{B609E0A0-5050-4871-91D6-E760633BCDD1}.PGO Optimize|Any CPU.ActiveCfg = PGO Optimize|Win32
@ -322,6 +327,29 @@ Global
{B609E0A0-5050-4871-91D6-E760633BCDD1}.Release|x64.Build.0 = Release|x64
{B609E0A0-5050-4871-91D6-E760633BCDD1}.Release|x86.ActiveCfg = Release|Win32
{B609E0A0-5050-4871-91D6-E760633BCDD1}.Release|x86.Build.0 = Release|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.Debug|Any CPU.ActiveCfg = Debug|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.Debug|x64.ActiveCfg = Debug|x64
{4432139E-528B-44DE-961C-B37CD5E92E0E}.Debug|x86.ActiveCfg = Debug|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.Debug|x86.Build.0 = Debug|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.Libretro|Any CPU.ActiveCfg = Libretro|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.Libretro|x64.ActiveCfg = Libretro|x64
{4432139E-528B-44DE-961C-B37CD5E92E0E}.Libretro|x64.Build.0 = Libretro|x64
{4432139E-528B-44DE-961C-B37CD5E92E0E}.Libretro|x86.ActiveCfg = Libretro|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.Libretro|x86.Build.0 = Libretro|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Optimize|Any CPU.ActiveCfg = Libretro|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Optimize|Any CPU.Build.0 = Libretro|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Optimize|x64.ActiveCfg = Libretro|x64
{4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Optimize|x86.ActiveCfg = Libretro|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Optimize|x86.Build.0 = Libretro|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Profile|Any CPU.ActiveCfg = Libretro|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Profile|Any CPU.Build.0 = Libretro|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Profile|x64.ActiveCfg = Libretro|x64
{4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Profile|x86.ActiveCfg = Libretro|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Profile|x86.Build.0 = Libretro|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.Release|Any CPU.ActiveCfg = Release|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.Release|x64.ActiveCfg = Release|x64
{4432139E-528B-44DE-961C-B37CD5E92E0E}.Release|x86.ActiveCfg = Release|Win32
{4432139E-528B-44DE-961C-B37CD5E92E0E}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -24,9 +24,7 @@ The following should be added over time (in no particular order):
* Netplay
* Cheats
* Additions/improvements in the debugging tools
* Lua scripting
* Support for the enhancement chips used in some games
* Libretro core (once the emulation core is stable/accurate enough)
## Compiling

View File

@ -63,7 +63,7 @@ endif
OBJFOLDER=obj.$(MESENPLATFORM)
SHAREDLIB=libMesenSCore.$(MESENPLATFORM).dll
LIBRETROLIB=mesens_libretro.$(MESENPLATFORM).so
LIBRETROLIB=mesen-s_libretro.$(MESENPLATFORM).so
RELEASEFOLDER=bin/$(MESENPLATFORM)/Release
COREOBJ=$(patsubst Core/%.cpp,Core/$(OBJFOLDER)/%.o,$(wildcard Core/*.cpp))
@ -143,10 +143,10 @@ InteropDLL/$(OBJFOLDER)/$(SHAREDLIB): $(SEVENZIPOBJ) $(LUAOBJ) $(UTILOBJ) $(CORE
cp $(SHAREDLIB) bin/pgohelperlib.so
mv $(SHAREDLIB) InteropDLL/$(OBJFOLDER)
Libretro/$(OBJFOLDER)/$(LIBRETROLIB): $(SEVENZIPOBJ) $(UTILOBJ) $(COREOBJ) $(LUAOBJ) Libretro/libretro.cpp
Libretro/$(OBJFOLDER)/$(LIBRETROLIB): $(SEVENZIPOBJ) $(UTILOBJ) $(COREOBJ) Libretro/libretro.cpp
mkdir -p bin
mkdir -p Libretro/$(OBJFOLDER)
$(CPPC) $(GCCOPTIONS) -Wl,-z,defs -shared -o $(LIBRETROLIB) Libretro/*.cpp $(SEVENZIPOBJ) $(UTILOBJ) $(COREOBJ) $(LUAOBJ) -pthread $(FSLIB)
$(CPPC) $(GCCOPTIONS) -Wl,-z,defs -shared -o $(LIBRETROLIB) Libretro/*.cpp $(SEVENZIPOBJ) $(UTILOBJ) $(COREOBJ) -pthread
cp $(LIBRETROLIB) bin/pgohelperlib.so
mv $(LIBRETROLIB) Libretro/$(OBJFOLDER)