libretro: Implement disk control interface

This commit is contained in:
Connor McLaughlin 2020-07-23 02:36:23 +10:00
parent 8e1c0a4fe4
commit f3df4f91a2
5 changed files with 218 additions and 2 deletions

View File

@ -1,6 +1,6 @@
#include "string_util.h"
#include <cstdio>
#include <cctype>
#include <cstdio>
namespace StringUtil {
@ -137,7 +137,23 @@ std::size_t Strlcpy(char* dst, const char* src, std::size_t size)
else
{
std::memcpy(dst, src, size - 1);
dst[size] = '\0';
dst[size - 1] = '\0';
}
return len;
}
std::size_t Strlcpy(char* dst, const std::string_view& src, std::size_t size)
{
std::size_t len = src.length();
if (len < size)
{
std::memcpy(dst, src.data(), len);
dst[len] = '\0';
}
else
{
std::memcpy(dst, src.data(), size - 1);
dst[size - 1] = '\0';
}
return len;
}

View File

@ -5,6 +5,7 @@
#include <cstring>
#include <optional>
#include <string>
#include <string_view>
#if defined(__has_include) && __has_include(<charconv>)
#include <charconv>
@ -27,6 +28,9 @@ bool WildcardMatch(const char* subject, const char* mask, bool case_sensitive =
/// Safe version of strlcpy.
std::size_t Strlcpy(char* dst, const char* src, std::size_t size);
/// Strlcpy from string_view.
std::size_t Strlcpy(char* dst, const std::string_view& src, std::size_t size);
/// Platform-independent strcasecmp
static inline int Strcasecmp(const char* s1, const char* s2)
{

View File

@ -27,6 +27,7 @@ Log_SetChannel(LibretroHostInterface);
#endif
LibretroHostInterface g_libretro_host_interface;
#define P_THIS (&g_libretro_host_interface)
retro_environment_t g_retro_environment_callback;
retro_video_refresh_t g_retro_video_refresh_callback;
@ -232,6 +233,7 @@ bool LibretroHostInterface::retro_load_game(const struct retro_game_info* game)
{
SystemBootParameters bp;
bp.filename = game->path;
bp.media_playlist_index = m_next_disc_index.value_or(0);
bp.force_software_renderer = !m_hw_render_callback_valid;
if (!BootSystem(bp))
@ -907,3 +909,180 @@ void LibretroHostInterface::SwitchToSoftwareRenderer()
m_display = std::make_unique<LibretroHostDisplay>();
m_system->RecreateGPU(GPURenderer::Software);
}
bool LibretroHostInterface::DiskControlSetEjectState(bool ejected)
{
System* system = P_THIS->GetSystem();
if (!system)
{
Log_ErrorPrintf("DiskControlSetEjectState() - no system");
return false;
}
Log_DevPrintf("DiskControlSetEjectState(%u)", static_cast<unsigned>(ejected));
if (ejected)
{
if (!system->HasMedia())
return false;
system->RemoveMedia();
return true;
}
else
{
const u32 image_to_insert = P_THIS->m_next_disc_index.value_or(0);
Log_DevPrintf("Inserting image %u", image_to_insert);
return system->SwitchMediaFromPlaylist(image_to_insert);
}
}
bool LibretroHostInterface::DiskControlGetEjectState()
{
System* system = P_THIS->GetSystem();
if (!system)
{
Log_ErrorPrintf("DiskControlGetEjectState() - no system");
return false;
}
Log_DevPrintf("DiskControlGetEjectState() -> %u", static_cast<unsigned>(system->HasMedia()));
return system->HasMedia();
}
unsigned LibretroHostInterface::DiskControlGetImageIndex()
{
System* system = P_THIS->GetSystem();
if (!system)
{
Log_ErrorPrintf("DiskControlGetImageIndex() - no system");
return false;
}
const u32 index = P_THIS->m_next_disc_index.value_or(system->GetMediaPlaylistIndex());
Log_DevPrintf("DiskControlGetImageIndex() -> %u", index);
return index;
}
bool LibretroHostInterface::DiskControlSetImageIndex(unsigned index)
{
System* system = P_THIS->GetSystem();
if (!system)
{
Log_ErrorPrintf("DiskControlSetImageIndex() - no system");
return false;
}
Log_DevPrintf("DiskControlSetImageIndex(%u)", index);
if (index >= system->GetMediaPlaylistCount())
return false;
P_THIS->m_next_disc_index = index;
return true;
}
unsigned LibretroHostInterface::DiskControlGetNumImages()
{
System* system = P_THIS->GetSystem();
if (!system)
{
Log_ErrorPrintf("DiskControlGetNumImages() - no system");
return false;
}
Log_DevPrintf("DiskControlGetNumImages() -> %u", system->GetMediaPlaylistCount());
return static_cast<unsigned>(system->GetMediaPlaylistCount());
}
bool LibretroHostInterface::DiskControlReplaceImageIndex(unsigned index, const retro_game_info* info)
{
System* system = P_THIS->GetSystem();
if (!system)
{
Log_ErrorPrintf("DiskControlReplaceImageIndex() - no system");
return false;
}
Log_DevPrintf("DiskControlReplaceImageIndex(%u, %s)", index, info ? info->path : "null");
if (info && info->path)
return system->ReplaceMediaPathFromPlaylist(index, info->path);
else
return system->RemoveMediaPathFromPlaylist(index);
}
bool LibretroHostInterface::DiskControlAddImageIndex()
{
System* system = P_THIS->GetSystem();
if (!system)
{
Log_ErrorPrintf("DiskControlAddImageIndex() - no system");
return false;
}
Log_DevPrintf("DiskControlAddImageIndex() -> %zu", system->GetMediaPlaylistCount());
system->AddMediaPathToPlaylist({});
return true;
}
bool LibretroHostInterface::DiskControlSetInitialImage(unsigned index, const char* path)
{
Log_DevPrintf("DiskControlSetInitialImage(%u, %s)", index, path);
P_THIS->m_next_disc_index = index;
return true;
}
bool LibretroHostInterface::DiskControlGetImagePath(unsigned index, char* path, size_t len)
{
System* system = P_THIS->GetSystem();
if (!system || index >= system->GetMediaPlaylistCount())
return false;
const std::string& image_path = system->GetMediaPlaylistPath(index);
Log_DevPrintf("DiskControlGetImagePath(%u) -> %s", index, image_path.c_str());
if (image_path.empty())
return false;
StringUtil::Strlcpy(path, image_path.c_str(), len);
return true;
}
bool LibretroHostInterface::DiskControlGetImageLabel(unsigned index, char* label, size_t len)
{
System* system = P_THIS->GetSystem();
if (!system || index >= system->GetMediaPlaylistCount())
return false;
const std::string& image_path = system->GetMediaPlaylistPath(index);
if (image_path.empty())
return false;
const std::string_view title = GameList::GetTitleForPath(label);
StringUtil::Strlcpy(label, title, len);
Log_DevPrintf("DiskControlGetImagePath(%u) -> %s", index, label);
return true;
}
void LibretroHostInterface::InitDiskControlInterface()
{
unsigned version = 0;
if (g_retro_environment_callback(RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION, &version) && version >= 1)
{
retro_disk_control_ext_callback ext_cb = {
&LibretroHostInterface::DiskControlSetEjectState, &LibretroHostInterface::DiskControlGetEjectState,
&LibretroHostInterface::DiskControlGetImageIndex, &LibretroHostInterface::DiskControlSetImageIndex,
&LibretroHostInterface::DiskControlGetNumImages, &LibretroHostInterface::DiskControlReplaceImageIndex,
&LibretroHostInterface::DiskControlAddImageIndex, &LibretroHostInterface::DiskControlSetInitialImage,
&LibretroHostInterface::DiskControlGetImagePath, &LibretroHostInterface::DiskControlGetImageLabel};
if (g_retro_environment_callback(RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE, &ext_cb))
return;
}
retro_disk_control_callback cb = {
&LibretroHostInterface::DiskControlSetEjectState, &LibretroHostInterface::DiskControlGetEjectState,
&LibretroHostInterface::DiskControlGetImageIndex, &LibretroHostInterface::DiskControlSetImageIndex,
&LibretroHostInterface::DiskControlGetNumImages, &LibretroHostInterface::DiskControlReplaceImageIndex,
&LibretroHostInterface::DiskControlAddImageIndex};
if (!g_retro_environment_callback(RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE, &cb))
Log_WarningPrint("Failed to set disk control interface");
}

View File

@ -2,6 +2,8 @@
#include "core/host_interface.h"
#include "core/system.h"
#include "libretro.h"
#include <limits>
#include <optional>
class LibretroHostInterface : public HostInterface
{
@ -12,6 +14,7 @@ public:
static void InitLogging();
static bool SetCoreOptions();
static bool HasCoreVariablesChanged();
static void InitDiskControlInterface();
ALWAYS_INLINE u32 GetResolutionScale() const { return m_settings.gpu_resolution_scale; }
@ -66,10 +69,23 @@ private:
static void HardwareRendererContextReset();
static void HardwareRendererContextDestroy();
// Disk control callbacks
static bool RETRO_CALLCONV DiskControlSetEjectState(bool ejected);
static bool RETRO_CALLCONV DiskControlGetEjectState();
static unsigned RETRO_CALLCONV DiskControlGetImageIndex();
static bool RETRO_CALLCONV DiskControlSetImageIndex(unsigned index);
static unsigned RETRO_CALLCONV DiskControlGetNumImages();
static bool RETRO_CALLCONV DiskControlReplaceImageIndex(unsigned index, const retro_game_info* info);
static bool RETRO_CALLCONV DiskControlAddImageIndex();
static bool RETRO_CALLCONV DiskControlSetInitialImage(unsigned index, const char* path);
static bool RETRO_CALLCONV DiskControlGetImagePath(unsigned index, char* path, size_t len);
static bool RETRO_CALLCONV DiskControlGetImageLabel(unsigned index, char* label, size_t len);
retro_hw_render_callback m_hw_render_callback = {};
std::unique_ptr<HostDisplay> m_hw_render_display;
bool m_hw_render_callback_valid = false;
bool m_using_hardware_renderer = false;
std::optional<u32> m_next_disc_index;
};
extern LibretroHostInterface g_libretro_host_interface;

View File

@ -127,6 +127,7 @@ RETRO_API void retro_set_environment(retro_environment_t f)
Log_WarningPrintf("Failed to set core options, settings will not be changeable.");
g_libretro_host_interface.InitLogging();
g_libretro_host_interface.InitDiskControlInterface();
}
RETRO_API void retro_set_video_refresh(retro_video_refresh_t f)