libretro: Implement disk control interface
This commit is contained in:
parent
8e1c0a4fe4
commit
f3df4f91a2
|
@ -1,6 +1,6 @@
|
||||||
#include "string_util.h"
|
#include "string_util.h"
|
||||||
#include <cstdio>
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
namespace StringUtil {
|
namespace StringUtil {
|
||||||
|
|
||||||
|
@ -137,7 +137,23 @@ std::size_t Strlcpy(char* dst, const char* src, std::size_t size)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::memcpy(dst, src, size - 1);
|
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;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#if defined(__has_include) && __has_include(<charconv>)
|
#if defined(__has_include) && __has_include(<charconv>)
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
|
@ -27,6 +28,9 @@ bool WildcardMatch(const char* subject, const char* mask, bool case_sensitive =
|
||||||
/// Safe version of strlcpy.
|
/// Safe version of strlcpy.
|
||||||
std::size_t Strlcpy(char* dst, const char* src, std::size_t size);
|
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
|
/// Platform-independent strcasecmp
|
||||||
static inline int Strcasecmp(const char* s1, const char* s2)
|
static inline int Strcasecmp(const char* s1, const char* s2)
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,6 +27,7 @@ Log_SetChannel(LibretroHostInterface);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LibretroHostInterface g_libretro_host_interface;
|
LibretroHostInterface g_libretro_host_interface;
|
||||||
|
#define P_THIS (&g_libretro_host_interface)
|
||||||
|
|
||||||
retro_environment_t g_retro_environment_callback;
|
retro_environment_t g_retro_environment_callback;
|
||||||
retro_video_refresh_t g_retro_video_refresh_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;
|
SystemBootParameters bp;
|
||||||
bp.filename = game->path;
|
bp.filename = game->path;
|
||||||
|
bp.media_playlist_index = m_next_disc_index.value_or(0);
|
||||||
bp.force_software_renderer = !m_hw_render_callback_valid;
|
bp.force_software_renderer = !m_hw_render_callback_valid;
|
||||||
|
|
||||||
if (!BootSystem(bp))
|
if (!BootSystem(bp))
|
||||||
|
@ -907,3 +909,180 @@ void LibretroHostInterface::SwitchToSoftwareRenderer()
|
||||||
m_display = std::make_unique<LibretroHostDisplay>();
|
m_display = std::make_unique<LibretroHostDisplay>();
|
||||||
m_system->RecreateGPU(GPURenderer::Software);
|
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");
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include "core/host_interface.h"
|
#include "core/host_interface.h"
|
||||||
#include "core/system.h"
|
#include "core/system.h"
|
||||||
#include "libretro.h"
|
#include "libretro.h"
|
||||||
|
#include <limits>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
class LibretroHostInterface : public HostInterface
|
class LibretroHostInterface : public HostInterface
|
||||||
{
|
{
|
||||||
|
@ -12,6 +14,7 @@ public:
|
||||||
static void InitLogging();
|
static void InitLogging();
|
||||||
static bool SetCoreOptions();
|
static bool SetCoreOptions();
|
||||||
static bool HasCoreVariablesChanged();
|
static bool HasCoreVariablesChanged();
|
||||||
|
static void InitDiskControlInterface();
|
||||||
|
|
||||||
ALWAYS_INLINE u32 GetResolutionScale() const { return m_settings.gpu_resolution_scale; }
|
ALWAYS_INLINE u32 GetResolutionScale() const { return m_settings.gpu_resolution_scale; }
|
||||||
|
|
||||||
|
@ -66,10 +69,23 @@ private:
|
||||||
static void HardwareRendererContextReset();
|
static void HardwareRendererContextReset();
|
||||||
static void HardwareRendererContextDestroy();
|
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 = {};
|
retro_hw_render_callback m_hw_render_callback = {};
|
||||||
std::unique_ptr<HostDisplay> m_hw_render_display;
|
std::unique_ptr<HostDisplay> m_hw_render_display;
|
||||||
bool m_hw_render_callback_valid = false;
|
bool m_hw_render_callback_valid = false;
|
||||||
bool m_using_hardware_renderer = false;
|
bool m_using_hardware_renderer = false;
|
||||||
|
std::optional<u32> m_next_disc_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern LibretroHostInterface g_libretro_host_interface;
|
extern LibretroHostInterface g_libretro_host_interface;
|
||||||
|
|
|
@ -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.");
|
Log_WarningPrintf("Failed to set core options, settings will not be changeable.");
|
||||||
|
|
||||||
g_libretro_host_interface.InitLogging();
|
g_libretro_host_interface.InitLogging();
|
||||||
|
g_libretro_host_interface.InitDiskControlInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
RETRO_API void retro_set_video_refresh(retro_video_refresh_t f)
|
RETRO_API void retro_set_video_refresh(retro_video_refresh_t f)
|
||||||
|
|
Loading…
Reference in New Issue