mirror of
https://github.com/libretro/dolphin
synced 2024-11-04 20:43:51 -05:00
379 lines
12 KiB
C++
379 lines
12 KiB
C++
#include <cstdio>
|
|
#include <libretro.h>
|
|
#include <string>
|
|
|
|
#include "Common/CommonPaths.h"
|
|
#include "Common/FileUtil.h"
|
|
#include "Core/Boot/Boot.h"
|
|
#include "Core/BootManager.h"
|
|
#include "Core/Config/GraphicsSettings.h"
|
|
#include "Core/Config/MainSettings.h"
|
|
#include "Core/Config/SYSCONFSettings.h"
|
|
#include "Core/ConfigManager.h"
|
|
#include "Core/Core.h"
|
|
#include "Core/HW/DVD/DVDInterface.h"
|
|
#include "Core/HW/VideoInterface.h"
|
|
#include "Core/PowerPC/PowerPC.h"
|
|
#include "DolphinLibretro/Input.h"
|
|
#include "DolphinLibretro/Log.h"
|
|
#include "DolphinLibretro/Options.h"
|
|
#include "DolphinLibretro/Video.h"
|
|
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
|
#include "UICommon/DiscordPresence.h"
|
|
#include "UICommon/UICommon.h"
|
|
#include "VideoCommon/AsyncRequests.h"
|
|
#include "VideoCommon/VideoBackendBase.h"
|
|
#include "VideoCommon/VideoConfig.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#include <filesystem>
|
|
namespace fs = std::filesystem;
|
|
#endif
|
|
|
|
namespace Libretro
|
|
{
|
|
extern retro_environment_t environ_cb;
|
|
|
|
// Disk swapping
|
|
static void InitDiskControlInterface();
|
|
static std::string NormalizePath(const std::string& path);
|
|
static std::string DenormalizePath(const std::string& path);
|
|
static unsigned disk_index = 0;
|
|
static bool eject_state;
|
|
static std::vector<std::string> disk_paths;
|
|
} // namespace Libretro
|
|
|
|
bool retro_load_game(const struct retro_game_info* game)
|
|
{
|
|
const char* save_dir = NULL;
|
|
const char* system_dir = NULL;
|
|
const char* core_assets_dir = NULL;
|
|
std::string user_dir;
|
|
std::string sys_dir;
|
|
|
|
Libretro::environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &save_dir);
|
|
Libretro::environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_dir);
|
|
Libretro::environ_cb(RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY, &core_assets_dir);
|
|
Libretro::InitDiskControlInterface();
|
|
|
|
if (save_dir && *save_dir)
|
|
user_dir = std::string(save_dir) + DIR_SEP "User";
|
|
else if (system_dir && *system_dir)
|
|
user_dir = std::string(system_dir) + DIR_SEP "dolphin-emu" DIR_SEP "User";
|
|
|
|
if (system_dir && *system_dir)
|
|
sys_dir = std::string(system_dir) + DIR_SEP "dolphin-emu" DIR_SEP "Sys";
|
|
else if (core_assets_dir && *core_assets_dir)
|
|
sys_dir = std::string(core_assets_dir) + DIR_SEP "dolphin-emu" DIR_SEP "Sys";
|
|
else if (save_dir && *save_dir)
|
|
sys_dir = std::string(save_dir) + DIR_SEP "Sys";
|
|
else
|
|
sys_dir = "dolphin-emu" DIR_SEP "Sys";
|
|
|
|
File::SetSysDirectory(sys_dir);
|
|
UICommon::SetUserDirectory(user_dir);
|
|
UICommon::CreateDirectories();
|
|
UICommon::Init();
|
|
Libretro::Log::Init();
|
|
Discord::SetDiscordPresenceEnabled(false);
|
|
Common::SetEnableAlert(false);
|
|
|
|
INFO_LOG(COMMON, "User Directory set to '%s'", user_dir.c_str());
|
|
INFO_LOG(COMMON, "System Directory set to '%s'", sys_dir.c_str());
|
|
|
|
/* disable throttling emulation to match GetTargetRefreshRate() */
|
|
Core::SetIsThrottlerTempDisabled(true);
|
|
SConfig::GetInstance().m_EmulationSpeed = Libretro::Options::EmulationSpeed;
|
|
|
|
#if defined(_DEBUG)
|
|
SConfig::GetInstance().bFastmem = false;
|
|
#else
|
|
SConfig::GetInstance().bFastmem = Libretro::Options::fastmem;
|
|
#endif
|
|
SConfig::GetInstance().bDSPHLE = Libretro::Options::DSPHLE;
|
|
SConfig::GetInstance().m_DSPEnableJIT = Libretro::Options::DSPEnableJIT;
|
|
SConfig::GetInstance().cpu_core = Libretro::Options::cpu_core;
|
|
SConfig::GetInstance().SelectedLanguage = (int)(DiscIO::Language)Libretro::Options::Language - 1;
|
|
SConfig::GetInstance().bCPUThread = true;
|
|
SConfig::GetInstance().bEMUThread = false;
|
|
SConfig::GetInstance().bBootToPause = true;
|
|
SConfig::GetInstance().m_OCFactor = Libretro::Options::cpuClockRate;
|
|
SConfig::GetInstance().m_OCEnable = Libretro::Options::cpuClockRate != 1.0;
|
|
SConfig::GetInstance().sBackend = BACKEND_NULLSOUND;
|
|
SConfig::GetInstance().m_DumpAudio = false;
|
|
SConfig::GetInstance().bDPL2Decoder = false;
|
|
SConfig::GetInstance().iLatency = 0;
|
|
SConfig::GetInstance().m_audio_stretch = false;
|
|
SConfig::GetInstance().m_WiimoteContinuousScanning = Libretro::Options::WiimoteContinuousScanning;
|
|
SConfig::GetInstance().bEnableCheats = Libretro::Options::cheatsEnabled;
|
|
SConfig::GetInstance().bOnScreenDisplayMessages = Libretro::Options::osdEnabled;
|
|
SConfig::GetInstance().bFastDiscSpeed = Libretro::Options::fastDiscSpeed;
|
|
|
|
Config::SetBase(Config::SYSCONF_LANGUAGE, (u32)(DiscIO::Language)Libretro::Options::Language);
|
|
Config::SetBase(Config::SYSCONF_WIDESCREEN, Libretro::Options::Widescreen);
|
|
Config::SetBase(Config::SYSCONF_PROGRESSIVE_SCAN, Libretro::Options::progressiveScan);
|
|
Config::SetBase(Config::SYSCONF_PAL60, Libretro::Options::pal60);
|
|
Config::SetBase(Config::SYSCONF_SENSOR_BAR_POSITION, Libretro::Options::sensorBarPosition);
|
|
Config::SetBase(Config::SYSCONF_WIIMOTE_MOTOR, Libretro::Options::enableRumble);
|
|
|
|
Config::SetBase(Config::GFX_WIDESCREEN_HACK, Libretro::Options::WidescreenHack);
|
|
Config::SetBase(Config::GFX_EFB_SCALE, Libretro::Options::efbScale);
|
|
Config::SetBase(Config::GFX_ASPECT_RATIO, AspectMode::Stretch);
|
|
Config::SetBase(Config::GFX_BACKEND_MULTITHREADING, false);
|
|
Config::SetBase(Config::GFX_SHADER_COMPILATION_MODE, Libretro::Options::shaderCompilationMode);
|
|
Config::SetBase(Config::GFX_ENHANCE_MAX_ANISOTROPY, Libretro::Options::maxAnisotropy);
|
|
Config::SetBase(Config::GFX_HACK_SKIP_DUPLICATE_XFBS, Libretro::Options::skipDupeFrames);
|
|
Config::SetBase(Config::GFX_HACK_IMMEDIATE_XFB, Libretro::Options::immediatexfb);
|
|
Config::SetBase(Config::GFX_HACK_COPY_EFB_SCALED, Libretro::Options::efbScaledCopy);
|
|
Config::SetBase(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, Libretro::Options::efbToTexture);
|
|
Config::SetBase(Config::GFX_HACK_DISABLE_COPY_TO_VRAM, Libretro::Options::efbToVram);
|
|
Config::SetBase(Config::GFX_FAST_DEPTH_CALC, Libretro::Options::fastDepthCalc);
|
|
Config::SetBase(Config::GFX_HACK_BBOX_ENABLE, Libretro::Options::bboxEnabled);
|
|
Config::SetBase(Config::GFX_ENABLE_GPU_TEXTURE_DECODING, Libretro::Options::gpuTextureDecoding);
|
|
Config::SetBase(Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING, Libretro::Options::waitForShaders);
|
|
Config::SetBase(Config::GFX_ENHANCE_FORCE_FILTERING, Libretro::Options::forceTextureFiltering);
|
|
Config::SetBase(Config::GFX_HIRES_TEXTURES, Libretro::Options::loadCustomTextures);
|
|
Config::SetBase(Config::GFX_CACHE_HIRES_TEXTURES, Libretro::Options::cacheCustomTextures);
|
|
Config::SetBase(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES, Libretro::Options::textureCacheAccuracy);
|
|
#if 0
|
|
Config::SetBase(Config::GFX_SHADER_COMPILER_THREADS, 1);
|
|
Config::SetBase(Config::GFX_SHADER_PRECOMPILER_THREADS, 1);
|
|
#endif
|
|
|
|
switch (Libretro::Options::antiAliasing)
|
|
{
|
|
case 1: // 2x MSAA
|
|
Config::SetBase(Config::GFX_MSAA, 2);
|
|
Config::SetBase(Config::GFX_SSAA, false);
|
|
break;
|
|
case 2: // 4x MSAA
|
|
Config::SetBase(Config::GFX_MSAA, 4);
|
|
Config::SetBase(Config::GFX_SSAA, false);
|
|
break;
|
|
case 3: // 8x MSAA
|
|
Config::SetBase(Config::GFX_MSAA, 8);
|
|
Config::SetBase(Config::GFX_SSAA, false);
|
|
break;
|
|
case 4: // 2x SSAA
|
|
Config::SetBase(Config::GFX_MSAA, 2);
|
|
Config::SetBase(Config::GFX_SSAA, true);
|
|
break;
|
|
case 5: // 4x SSAA
|
|
Config::SetBase(Config::GFX_MSAA, 4);
|
|
Config::SetBase(Config::GFX_SSAA, true);
|
|
break;
|
|
case 6: // 8x SSAA
|
|
Config::SetBase(Config::GFX_MSAA, 8);
|
|
Config::SetBase(Config::GFX_SSAA, true);
|
|
break;
|
|
default: // disabled
|
|
Config::SetBase(Config::GFX_MSAA, 1);
|
|
Config::SetBase(Config::GFX_SSAA, false);
|
|
break;
|
|
}
|
|
|
|
Libretro::Video::Init();
|
|
VideoBackendBase::PopulateBackendInfo();
|
|
NOTICE_LOG(VIDEO, "Using GFX backend: %s", Config::Get(Config::MAIN_GFX_BACKEND).c_str());
|
|
|
|
WindowSystemInfo wsi(WindowSystemType::Libretro, nullptr, nullptr, nullptr);
|
|
|
|
std::vector<std::string> normalized_game_paths;
|
|
normalized_game_paths.push_back(Libretro::NormalizePath(game->path));
|
|
std::string folder_path;
|
|
std::string extension;
|
|
SplitPath(normalized_game_paths.front(), &folder_path, nullptr, &extension);
|
|
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
|
|
|
if (extension == ".m3u" || extension == ".m3u8")
|
|
{
|
|
normalized_game_paths = ReadM3UFile(normalized_game_paths.front(), folder_path);
|
|
if (normalized_game_paths.empty())
|
|
{
|
|
ERROR_LOG(BOOT, "Could not boot %s. M3U contains no paths\n", game->path);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (auto& normalized_game_path : normalized_game_paths)
|
|
Libretro::disk_paths.push_back(Libretro::DenormalizePath(normalized_game_path));
|
|
|
|
if (!BootManager::BootCore(BootParameters::GenerateFromFile(normalized_game_paths), wsi))
|
|
{
|
|
ERROR_LOG(BOOT, "Could not boot %s\n", game->path);
|
|
return false;
|
|
}
|
|
|
|
Libretro::Input::Init();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool retro_load_game_special(unsigned game_type, const struct retro_game_info* info,
|
|
size_t num_info)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void retro_unload_game(void)
|
|
{
|
|
Core::Stop();
|
|
Core::Shutdown();
|
|
g_video_backend->ShutdownShared();
|
|
Libretro::Input::Shutdown();
|
|
Libretro::Log::Shutdown();
|
|
UICommon::Shutdown();
|
|
}
|
|
|
|
namespace Libretro
|
|
{
|
|
// Disk swapping
|
|
|
|
// Dolphin expects to be able to use "/" (DIR_SEP) everywhere.
|
|
// RetroArch uses the OS separator.
|
|
// Convert between them when switching between systems.
|
|
std::string NormalizePath(const std::string& path)
|
|
{
|
|
std::string newPath = path;
|
|
#ifdef _MSC_VER
|
|
constexpr fs::path::value_type os_separator = fs::path::preferred_separator;
|
|
static_assert(os_separator == DIR_SEP_CHR || os_separator == '\\', "Unsupported path separator");
|
|
if (os_separator != DIR_SEP_CHR)
|
|
std::replace(newPath.begin(), newPath.end(), '\\', DIR_SEP_CHR);
|
|
#endif
|
|
|
|
return newPath;
|
|
}
|
|
|
|
std::string DenormalizePath(const std::string& path)
|
|
{
|
|
std::string newPath = path;
|
|
#ifdef _MSC_VER
|
|
constexpr fs::path::value_type os_separator = fs::path::preferred_separator;
|
|
static_assert(os_separator == DIR_SEP_CHR || os_separator == '\\', "Unsupported path separator");
|
|
if (os_separator != DIR_SEP_CHR)
|
|
std::replace(newPath.begin(), newPath.end(), DIR_SEP_CHR, '\\');
|
|
#endif
|
|
|
|
return newPath;
|
|
}
|
|
|
|
static bool retro_set_eject_state(bool ejected)
|
|
{
|
|
if (eject_state == ejected)
|
|
return false;
|
|
|
|
eject_state = ejected;
|
|
|
|
if (!ejected)
|
|
{
|
|
if (disk_index >= 0 && disk_index < (int)disk_paths.size())
|
|
{
|
|
Core::RunAsCPUThread([] { DVDInterface::ChangeDisc(NormalizePath(disk_paths[disk_index])); });
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool retro_get_eject_state()
|
|
{
|
|
return eject_state;
|
|
}
|
|
|
|
static unsigned retro_get_image_index()
|
|
{
|
|
return disk_index;
|
|
}
|
|
|
|
static bool retro_set_image_index(unsigned index)
|
|
{
|
|
if (eject_state)
|
|
disk_index = index;
|
|
|
|
return eject_state;
|
|
}
|
|
|
|
static unsigned retro_get_num_images()
|
|
{
|
|
return (unsigned)disk_paths.size();
|
|
}
|
|
|
|
static bool retro_add_image_index()
|
|
{
|
|
disk_paths.push_back("");
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool retro_replace_image_index(unsigned index, const struct retro_game_info* info)
|
|
{
|
|
if (index >= disk_paths.size())
|
|
return false;
|
|
|
|
if (!info->path)
|
|
{
|
|
disk_paths.erase(disk_paths.begin() + index);
|
|
if (!disk_paths.size())
|
|
disk_index = -1;
|
|
else if (disk_index > (int)index)
|
|
disk_index--;
|
|
}
|
|
else
|
|
disk_paths[index] = info->path;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool RETRO_CALLCONV retro_set_initial_image(unsigned index, const char* path)
|
|
{
|
|
if (index >= disk_paths.size())
|
|
index = 0;
|
|
|
|
disk_index = index;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool RETRO_CALLCONV retro_get_image_path(unsigned index, char* path, size_t len)
|
|
{
|
|
if (index >= disk_paths.size())
|
|
return false;
|
|
|
|
if (disk_paths[index].empty())
|
|
return false;
|
|
|
|
strncpy(path, disk_paths[index].c_str(), len);
|
|
return true;
|
|
}
|
|
static bool RETRO_CALLCONV retro_get_image_label(unsigned index, char* label, size_t len)
|
|
{
|
|
if (index >= disk_paths.size())
|
|
return false;
|
|
|
|
if (disk_paths[index].empty())
|
|
return false;
|
|
|
|
strncpy(label, disk_paths[index].c_str(), len);
|
|
return true;
|
|
}
|
|
|
|
static void InitDiskControlInterface()
|
|
{
|
|
static retro_disk_control_ext_callback disk_control = {
|
|
retro_set_eject_state,
|
|
retro_get_eject_state,
|
|
retro_get_image_index,
|
|
retro_set_image_index,
|
|
retro_get_num_images,
|
|
retro_replace_image_index,
|
|
retro_add_image_index,
|
|
retro_set_initial_image,
|
|
retro_get_image_path,
|
|
retro_get_image_label,
|
|
};
|
|
|
|
environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE, &disk_control);
|
|
}
|
|
} // namespace Libretro
|