Skip to content

Update libretro-common to latest upstream#106

Open
JoeMatt wants to merge 49 commits intolibretro:masterfrom
Provenance-Emu:libretro/feature/update-libretro-common
Open

Update libretro-common to latest upstream#106
JoeMatt wants to merge 49 commits intolibretro:masterfrom
Provenance-Emu:libretro/feature/update-libretro-common

Conversation

@JoeMatt
Copy link
Copy Markdown
Collaborator

@JoeMatt JoeMatt commented Apr 4, 2026

Summary

  • Updates vendored libretro-common/ from ~October 2021 to the latest upstream (2025)
  • 33 files changed, +11,175 / -5,082 lines across headers and source files
  • Builds cleanly on macOS (Clang) with no new warnings

Refs #105

Key changes from upstream

  • libretro.h — massively expanded with 4+ years of new libretro API additions
  • file_path.c — significant refactoring
  • vfs_implementation.c / vfs_implementation_uwp.cpp — major rework
  • retro_endianness.h / retro_miscellaneous.h — substantial updates
  • stdstring.c / stdstring.h — many new utility functions

Test plan

  • CI builds pass on Linux (GCC) and macOS (Clang)
  • Load and run a game to verify no runtime regressions
  • Verify EEPROM save/load still works (uses VFS layer)

🤖 Generated with Claude Code

The bit shifting and masking is expensive on ARM64 for some reason.
The unions seem to greatly reduce the perfomance hit of these common calls.
The values for offset0 and offset1 were coming out to 63 when they should be no more than 3. I think the devide should have beena modulus? I wrote out the code with more vars to figure ouit what was going on
looking at the offical shamusworld repo the division was moved after the 0xFF checks
GPU_RUNNING running macro was pretty slow on ARM for some reason. Bitswise structs are faster in my testing
Signed-off-by: Joe Mattiello <mail@joemattiello.com>
Signed-off-by: Joe Mattiello <mail@joemattiello.com>
Signed-off-by: Joe Mattiello <mail@joemattiello.com>
Signed-off-by: Joseph Mattello <mail@joemattiello.com>
The bit shifting and masking is expensive on ARM64 for some reason.
The unions seem to greatly reduce the perfomance hit of these common calls.

byte pack struct

Move memory structs to header

Disable some of my speed hacks to test mem corruption

Wrap more of my structs in ifdefs for testing

Signed-off-by: Joseph Mattello <mail@joemattiello.com>
Signed-off-by: Joseph Mattello <mail@joemattiello.com>
GPU_RUNNING running macro was pretty slow on ARM for some reason. Bitswise structs are faster in my testing

Try some blitter optimizations

blitter sign fixes

Signed-off-by: Joe Mattiello <mail@joemattiello.com>

Comment out unused simd import

Signed-off-by: Joe Mattiello <mail@joemattiello.com>

Try some GPU optimizations and clarity

post rebase cleanup

Signed-off-by: Joseph Mattello <mail@joemattiello.com>

Remove USE_STRUCTS ifdef

Signed-off-by: Joseph Mattello <mail@joemattiello.com>

gpu.c Fix bad return

Signed-off-by: Joseph Mattello <mail@joemattiello.com>

Fix gpu opcode bad merge

Signed-off-by: Joseph Mattello <mail@joemattiello.com>

remove duplicate struct defs

Signed-off-by: Joseph Mattello <mail@joemattiello.com>
Signed-off-by: Joseph Mattello <mail@joemattiello.com>
Signed-off-by: Joseph Mattello <mail@joemattiello.com>
GPU_RUNNING running macro was pretty slow on ARM for some reason. Bitswise structs are faster in my testing

Try some blitter optimizations

blitter sign fixes

Signed-off-by: Joe Mattiello <mail@joemattiello.com>

Comment out unused simd import

Signed-off-by: Joe Mattiello <mail@joemattiello.com>

Try some GPU optimizations and clarity

post rebase cleanup

Signed-off-by: Joseph Mattello <mail@joemattiello.com>

Remove USE_STRUCTS ifdef

Signed-off-by: Joseph Mattello <mail@joemattiello.com>

gpu.c Fix bad return

Signed-off-by: Joseph Mattello <mail@joemattiello.com>

Fix gpu opcode bad merge

Signed-off-by: Joseph Mattello <mail@joemattiello.com>

remove duplicate struct defs

Signed-off-by: Joseph Mattello <mail@joemattiello.com>
JoeMatt and others added 19 commits October 14, 2021 19:12
GPU_RUNNING running macro was pretty slow on ARM for some reason. Bitswise structs are faster in my testing

Signed-off-by: Joseph Mattello <mail@joemattiello.com>
Signed-off-by: Joseph Mattello <mail@joemattiello.com>
Signed-off-by: Joseph Mattello <mail@joemattiello.com>
Signed-off-by: Joseph Mattello <mail@joemattiello.com>
Signed-off-by: Joseph Mattello <mail@joemattiello.com>

# Conflicts:
#	src/blitter.c
#	src/dsp.c
#	src/gpu.c
#	src/joystick.c
Signed-off-by: Joseph Mattello <mail@joemattiello.com>

# Conflicts:
#	src/blitter.c
#	src/dsp.c
#	src/gpu.c
#	src/joystick.c
#	src/vjag_memory.h
Signed-off-by: Joe Mattiello <mail@joemattiello.com>
Signed-off-by: Joseph Mattello <mail@joemattiello.com>
Fix Jaguar Emulation in Provenance
Update vendored libretro-common from ~Oct 2021 to current upstream.
Brings 4+ years of bug fixes, new API support, platform compatibility
improvements, and security fixes.

Refs libretro#105

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 4, 2026 03:00
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the project’s vendored libretro-common/ to the current upstream (2025-era) and adapts the core to newer libretro APIs (core options v2, updated VFS/file helpers, and related compatibility utilities).

Changes:

  • Vendor refresh of libretro-common (headers + implementations) including VFS, string, encoding, and file stream layers
  • Migrates core options to the modern libretro_core_options helper and expands input remapping support
  • Minor core-side fixes/adjustments (e.g., GPU offset check, joystick handling, tvOS min-version flags)

Reviewed changes

Copilot reviewed 38 out of 39 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/joystick.c Small joystick masking/offset handling adjustments
src/gpu.c Fixes GPU register address comparison logic
Makefile Adds tvOS min deployment version flags
libretro.c Switches to core options helper; adds extensive input remapping logic
libretro-common/time/rtime.c Updates rtime init/deinit behavior around thread lock
libretro-common/string/stdstring.c Upstream string utilities refactor + new helpers
libretro-common/streams/file_stream.c Major file stream refactor; adds copy/compare helpers
libretro-common/streams/file_stream_transforms.c Safer stdio-like wrappers and mode parsing
libretro-common/include/vfs/vfs.h Extends VFS scheme enum/struct fields and includes
libretro-common/include/vfs/vfs_implementation.h Adds WinRT ACL helper declaration
libretro-common/include/time/rtime.h Expands/clarifies rtime API documentation
libretro-common/include/string/stdstring.h Updates APIs/signatures and adds new helpers
libretro-common/include/streams/file_stream.h Large doc+API expansion (copy/cmp/scanf/etc.)
libretro-common/include/streams/file_stream_transforms.h Adds docs and improves wrapper safety
libretro-common/include/retro_miscellaneous.h Updates constants and expands utility macros/docs
libretro-common/include/retro_inline.h Adds inline macro documentation
libretro-common/include/retro_environment.h Removes dead debug block
libretro-common/include/retro_endianness.h Expands endianness/docs and modernizes detection
libretro-common/include/retro_common.h Updates header comment and internal docs
libretro-common/include/retro_common_api.h Tightens Apple detection; adds deprecation macro
libretro-common/include/file/file_path.h Adds/changes path APIs and documentation
libretro-common/include/encodings/utf.h Adds documentation and clarifies ownership rules
libretro-common/include/compat/strl.h Adds docs and Apple gating; declares strldup
libretro-common/include/compat/strcasestr.h Adds documentation for portable strcasestr
libretro-common/include/compat/posix_string.h Adds documentation and broadens platform gating
libretro-common/include/compat/msvc.h Renames params for snprintf wrappers
libretro-common/file/file_path_io.c Removes assertions/includes and updates path APIs
libretro-common/encodings/encoding_utf.c Performance refactors; Win32 conversion paths updated
libretro-common/compat/fopen_utf8.c Improves resource handling and early returns
libretro-common/compat/compat_strl.c Updates strlcpy/strlcat implementation and platform gating
libretro-common/compat/compat_strcasestr.c Minor refactor of portable implementation
libretro-common/compat/compat_snprintf.c Minor refactor/renaming for snprintf compatibility
libretro-common/compat/compat_posix_string.c Refactors strdup implementation
libretro_core_options.h New generated core options v2 definitions + helper
libretro_core_options_intl.h New i18n stub header (BOM/UTF-8 handling)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +472 to +485
RFILE *fp_dst = filestream_open(dst, RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE);

if (!fp_src || !fp_dst)
ret = -1;

if (ret < 0)
goto close;

snprintf(path_dst, sizeof(path_dst), "%s", dst);
path_basedir(path_dst);

if (!path_is_directory(path_dst))
path_mkdir(path_dst);

Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filestream_copy() opens the destination file before ensuring the destination directory exists. If the directory is missing, opening dst will fail and the later path_mkdir() call is never reached, so the copy cannot succeed. Create the destination directory (based on dst) before calling filestream_open() for the output file, or retry opening after a successful mkdir.

Suggested change
RFILE *fp_dst = filestream_open(dst, RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!fp_src || !fp_dst)
ret = -1;
if (ret < 0)
goto close;
snprintf(path_dst, sizeof(path_dst), "%s", dst);
path_basedir(path_dst);
if (!path_is_directory(path_dst))
path_mkdir(path_dst);
RFILE *fp_dst = NULL;
snprintf(path_dst, sizeof(path_dst), "%s", dst);
path_basedir(path_dst);
if (!path_is_directory(path_dst))
path_mkdir(path_dst);
fp_dst = filestream_open(dst, RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!fp_src || !fp_dst)
ret = -1;
if (ret < 0)
goto close;

Copilot uses AI. Check for mistakes.
Comment on lines +515 to +518
while ((filestream_read(fp_src, buf_src, sizeof(buf_src))) > 0 && ret == 0)
{
filestream_read(fp_dst, buf_dst, sizeof(buf_dst));
ret = memcmp(buf_src, buf_dst, sizeof(buf_src));
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filestream_cmp() compares sizeof(buf_src) bytes each iteration regardless of how many bytes were actually read. On the final chunk (or on short reads), this can compare stale bytes from the previous loop iteration and yield incorrect non-zero results. Track the number of bytes read from the source and compare only that many bytes (and validate the destination read matches).

Suggested change
while ((filestream_read(fp_src, buf_src, sizeof(buf_src))) > 0 && ret == 0)
{
filestream_read(fp_dst, buf_dst, sizeof(buf_dst));
ret = memcmp(buf_src, buf_dst, sizeof(buf_src));
int src_read = 0;
int dst_read = 0;
while ((src_read = filestream_read(fp_src, buf_src, sizeof(buf_src))) > 0 && ret == 0)
{
dst_read = filestream_read(fp_dst, buf_dst, (size_t)src_read);
if (dst_read != src_read)
{
ret = -1;
break;
}
ret = memcmp(buf_src, buf_dst, (size_t)src_read);

Copilot uses AI. Check for mistakes.
int filestream_eof(RFILE *stream)
{
return stream->eof_flag;
return filestream_tell(stream) == filestream_get_size(stream) ? EOF : 0;
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filestream_eof() treats a stream as EOF when tell() equals get_size(). If either function returns VFS_ERROR_RETURN_VALUE (e.g., -1) and both match, this reports EOF even though an error occurred. Consider returning EOF only when both calls succeed (non-negative) and sizes match, or use an internal EOF flag based on read results.

Suggested change
return filestream_tell(stream) == filestream_get_size(stream) ? EOF : 0;
int64_t current_position = filestream_tell(stream);
int64_t stream_size = filestream_get_size(stream);
if (current_position != VFS_ERROR_RETURN_VALUE &&
stream_size != VFS_ERROR_RETURN_VALUE &&
current_position == stream_size)
return EOF;
return 0;

Copilot uses AI. Check for mistakes.
Comment on lines +581 to +590
if ((_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)))
{
buf = (wchar_t*)calloc(len, sizeof(wchar_t));

if (!buf)
if (!(buf = (wchar_t*)calloc(_len, sizeof(wchar_t))))
return NULL;

out_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len);
if ((MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, _len)) < 0)
{
free(buf);
return NULL;
}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Windows, MultiByteToWideChar() signals failure by returning 0 (not a negative value). The current < 0 check will never trigger, so conversion failures can return a buffer containing uninitialized/partial data. Update the error check to handle a 0 return value and free/return NULL appropriately.

Copilot uses AI. Check for mistakes.
Comment on lines +655 to 663
if (!(buf = (char*)calloc(_len, sizeof(char))))
return NULL;

if (WideCharToMultiByte(code_page,
0, str, -1, buf, len, NULL, NULL) < 0)
0, str, -1, buf, _len, NULL, NULL) < 0)
{
free(buf);
return NULL;
}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Windows, WideCharToMultiByte() signals failure by returning 0 (not a negative value). The current < 0 check will not catch errors, potentially returning an invalid buffer. Check for a 0 return value and handle failure by freeing/returning NULL.

Copilot uses AI. Check for mistakes.
Comment on lines +73 to 83
/**
* A version of \c strndup(3) that guarantees the result will be null-terminated.
*
* @param s The string to duplicate.
* @param n The maximum number of characters to copy from \c s.
* The result will allocate one more byte than this value.
* @return Pointer to the cloned string.
* Must be freed with \c free().
*/
char *strldup(const char *s, size_t n);

Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strldup() is declared in include/compat/strl.h, but there is no implementation in the repository (it was removed from compat_strl.c). This will cause linker errors if any code uses strldup(). Either restore an implementation (e.g., allocate n+1, copy at most n bytes, and NUL-terminate) or remove the declaration/API if it’s no longer intended to be provided.

Suggested change
/**
* A version of \c strndup(3) that guarantees the result will be null-terminated.
*
* @param s The string to duplicate.
* @param n The maximum number of characters to copy from \c s.
* The result will allocate one more byte than this value.
* @return Pointer to the cloned string.
* Must be freed with \c free().
*/
char *strldup(const char *s, size_t n);

Copilot uses AI. Check for mistakes.
Comment on lines 39 to 43
rtime_deinit();
#ifdef HAVE_THREADS
if (!rtime_localtime_lock)
rtime_localtime_lock = slock_new();

retro_assert(rtime_localtime_lock);
#endif
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rtime_init() no longer asserts that slock_new() succeeded, but rtime_localtime() unconditionally locks rtime_localtime_lock. If allocation fails, this will dereference/lock a NULL pointer. Add a NULL check after slock_new() and either fall back to non-thread-safe behavior or make rtime_localtime() gracefully handle a missing lock.

Copilot uses AI. Check for mistakes.
Comment on lines 195 to 205
/**
* path_parent_dir:
* @path : path
* @s : path
* @len : size of buffer
*
* Extracts parent directory by mutating path.
* Assumes that path is a directory. Keeps trailing '/'.
* If the path was already at the root directory, returns empty string
**/
void path_parent_dir(char *path);
size_t path_parent_dir(char *s, size_t len);

Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The path_parent_dir() header docs describe len as the buffer size, but the implementation treats it as the current string length (callers pass strlen() / strlcpy() return values). This mismatch is likely to cause incorrect future usage. Update the parameter documentation to match the actual expected value (string length, not capacity).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants