7562 Commits
Author SHA1 Message Date
scribam 9f4ad6d6db android: update oboe and project 2026-11-08 18:11:36 +01:00
Flyinghead 8aec4a9220 elan: raise YUV_DMA interrupt when DMA is done
Fixes initdo texture corruption on start screen.
Issue #2101
[ci skip]
2026-11-08 18:10:56 +01:00
Flyinghead b6f03ecca2 msvc build fix
[ci skip]
2026-11-08 18:07:32 +01:00
Flyinghead 4600d08dbb wccf: add naomi:WCCFNode config. Handle socket to port 59200 locally
Replace naomi:WCCFSlave by naomi:WCCFNode to set node number for
projectors and satellites.
Handle socket to port 59200 locally to allow connecting from the same IP
and bypass wccfd completely.
2026-11-08 17:14:23 +01:00
Flyinghead 03e5704908 libretro: disable capcom direct on android 2026-11-08 16:35:05 +01:00
davey a14c02e2bd libretro: enable the Vulkan device extensions the frontend requires
The context negotiation interface passes the device extensions the
frontend needs, but they were never enabled. Frontends such as RetroArch
pass the extensions an OpenXR runtime needs to share the device, and
without them SteamVR crashes in xrCreateSession.
2026-11-04 18:34:34 +01:00
Flyinghead 802874e79d arm64 linux: get page size at runtime. Upload symbols to sentry 2026-11-02 14:59:56 +01:00
raph 1fac3d3fef libretro build fix 2026-11-01 18:38:49 +01:00
James 800d0ec2d8 Added arm64-linux build to CI (#2596)
* Added linux-arm64 build (aarch64) to CI
* Run unit tests on linux-arm64 build
2026-11-01 18:04:39 +01:00
Alex Stapleton 6a6038f910 picotcp: make room for more than ~1,000 timers (#2595)
The timer heap is capped at MAX_BLOCK_COUNT blocks of 1600 bytes, about
1,050 timers. Each TCP socket keeps several (keepalive, stats,
retransmission, linger) and closed sockets linger for 30 seconds, so a few
dozen connections a second fill it. When pico_timer_add() fails,
socket_del() frees the socket at once instead of deferring it, while
pico_tcp_input() is still using it: AddressSanitizer reports a
heap-use-after-free in pico_tcp_input(), and release builds crash.

Raise the cap to 1024 blocks (~67,000 timers). There is a single heap, and
blocks are only allocated as it grows, so this costs 8 KB of pointers.
[ci skip]
2026-11-01 18:04:12 +01:00
Alex Stapleton f86e4c6ea4 picotcp: don't connect a socket whose quad is already in use (#2594)
pico_socket_connect() ignored the result of pico_socket_alter_state(),
which fails when a socket with the same local/remote address and port is
already in the socket tree. The new socket then carried on untracked, and
deleting it later found and unlinked the other socket instead, which was
then freed while still in use: a double free or heap corruption.

picoppp hits this when it forwards an inbound connection whose client
reused a source port while picotcp still holds the previous connection
(Linux reuses loopback source ports at once). Fail the connect with
EADDRINUSE, and have picoppp retry with a port picotcp picks.

Found by forwarding a few hundred connections a second to the Broadband
Adapter; the crash went away with this.
[ci skip]
2026-11-01 18:03:52 +01:00
Alex Stapleton 7b1df94c8e picoppp: don't terminate when shutting down a disconnected host socket (#2593)
TcpSocket called the throwing overloads of asio's socket.shutdown() and
socket.close() when the guest closed its side of a connection. If the
host peer had already disconnected (or reset the connection),
shutdown() throws std::system_error ("Transport endpoint is not
connected"), nothing catches it, and Flycast terminates.

Use the error_code overloads: a peer that is already gone just means the
socket is already closed.

Found forwarding a few hundred connections a second to a KallistiOS
program, where clients and guest close connections in either order:
Flycast terminated within about a thousand connections.
[ci skip]
2026-11-01 18:03:33 +01:00
Alex Stapleton 973e569a7d picotcp: fix double free racing pico_enqueue() with the pico thread (#2592)
Since c52e6cc, the emulation thread calls pico_stack_recv() directly,
which enqueues on the device's protected q_in while the pico thread
dequeues it. pico_enqueue() unlocked the queue and then read q->size for
its return value. If the pico thread dequeued and processed the frame in
between, the size could read 0, and pico_stack_recv() took that as a
failed enqueue and freed a frame the pico thread had already freed.

AddressSanitizer: attempting double-free in pico_stack_recv(), called
from qemu_send_packet() on the emulation thread; freed by
pico_ethernet_receive() on the pico thread. It took a few dozen
forwarded TCP connections to crash a release build.

Read the size under the lock. Also create the queue mutex in
pico_queue_protect(): creating it lazily on first lock can give the two
threads different mutexes.
[ci skip]
2026-11-01 18:03:11 +01:00
flyinghead 13cfe43858 Crowdin Translations
[ci skip]
2026-11-01 18:02:41 +01:00
Flyinghead e778e529be save to temp file then rename over previous one when possible
[ci skip]
2026-11-01 18:00:35 +01:00
Flyinghead 2c83abcce4 libretro: add libjuice to combined lib for switch 2026-10-28 14:41:20 +01:00
Flyinghead 07535d22e8 ci: enable macOS build 2026-10-28 14:39:11 +01:00
Flyinghead 98ceceed1e aica: decrease the aica DMA xfer rate from 25 MB/s to 16 MiB/s
Fixes NCAA College Football 2K2, NBA 2K and NFL 2K right music channel
getting louder.
Issue #2525
2026-10-28 14:37:54 +01:00
Flyinghead 23d212f4f0 ci: disable macOS build 2026-10-27 11:26:55 +01:00
Flyinghead 917a7552f9 disable openmp on macos 2026-10-26 14:20:23 +01:00
Flyinghead 697d15a133 naomi: drop support for .lst files 2026-10-26 13:08:42 +01:00
Flyinghead 34e1211871 mem: return non-null value when reading ext. device (area 5)
Fixes NHL 2K2 freeze when pressing DPad right on Credits menu.
Issue #2535
2026-10-26 12:38:16 +01:00
Flyinghead cd89ae96ab aica: decrease the aica DMA xfer rate from 50 to 25 MiB/s
Fixes NCAA College Football 2K2 right music channel getting louder.
Issue #2525
Small ADPCM decoding optimization
2026-10-26 12:29:50 +01:00
scribam 01db8a203e ci: use openbsd 8.0 (#2587)
[ci skip]
2026-10-26 10:27:20 +01:00
Joe Mattiello 6d49796a15 flashrom: write the flash and nvmem saves atomically (#2579)
WritableChip::Save() wrote the image in place. A crash or a kill while
it is being written leaves a truncated file: the Dreamcast then boots
into the date and time setup with its settings gone, and an arcade
board loses its nvmem (service settings, high scores, unlocked content).

Write to a temp file next to the real one, flush it, then rename it
over the real path, so the file on disk is always either the previous
image or the complete new one. On Windows, rename() refuses to replace
an existing file, so flycast::rename() (which had no callers) now uses
MoveFileEx with MOVEFILE_REPLACE_EXISTING, matching POSIX.

Testing: compiles on macOS arm64; the Windows path is not built here.

Co-authored-by: Claude Fable 5.1 <[email protected]>
[ci skip]
2026-10-26 10:26:57 +01:00
Joe Mattiello 907d15155e rend: NEON for the 0888 and 8888 framebuffer write paths on arm64 (#2557)
0888 KRGB and 8888 ARGB, still went through the scalar per-pixel writer.
One packed pixel is exactly one VRAM word, so they fit the same 8-word
interleaved store as the 16-bit path, 8 pixels per iteration. The store
is factored out of storeFramebuffer16Pixels() so both use it.

888 (24-bit packed) stays scalar: its pixels straddle VRAM words, so the
store pattern only repeats every 4 pixels / 3 words.

The address walk is the same as writeFramebufferLW(), so the output is
identical to the scalar path, including when the padding isn't a
multiple of 4. A harness writing 7,056 frames through both paths (both
channel orders, modes 4 to 6, 6 frame sizes, 7 destination addresses
including bank and VRAM edges, 7 line strides, 4 clip windows) gives
byte-identical VRAM. The same algorithm measured about 2x faster on a
640x480 8888 frame (0.213 ms to 0.105 ms) on Apple Silicon.

tests/src/rend/FramebufferWriteTest.cpp checks both 32-bit modes against
an independent reference (one pvr_write32p per pixel, the scalar walk)
over 3,600 cases: widths around the 8-pixel vector width, padding
including values that aren't a multiple of 4, destinations at the 32-bit
bank boundary and the end of VRAM, and clip windows, for both channel
orders. All of VRAM is compared, so a store past the frame fails too. On
arm64 it exercises the NEON path; elsewhere the scalar one. It fails when
the padding computation is deliberately broken.

Other architectures are unchanged.

Co-authored-by: Claude Opus 5.5 <[email protected]>
[ci skip]
2026-10-26 10:26:27 +01:00
Givo e2f1484571 changed achievement draw shortcut to return false rather than true 2026-10-24 17:24:35 +02:00
Will fe58ee8c20 add the ability to hide achievement popups 2026-10-24 17:24:35 +02:00
Joe Mattiello 7c22066aa3 tests: build and link the unit test binary on macOS (#2575)
ENABLE_CTEST=ON never produced a test runner on macOS. The app's main()
(shell/apple/emulator-osx/SDLApplicationDelegate.mm) was still compiled
in, so the binary launched the emulator UI instead of gtest_main, and the
link needed libcurl, which HttpTest uses directly while the core only
links curl where it is the HTTP client (not on Apple).

- Leave SDLApplicationDelegate.mm, osx-main.mm and the Syphon video
  routing out of the target when BUILD_TESTING is set, like linux-dist
  main.cpp and winmain.cpp already are.
- Stub the os_* / darw_printf / hostfs / i18n glue those files provided,
  in tests/src/test_stubs.cpp, for macOS.
- Link CURL::libcurl into the test target on Apple.

With this the suite builds with both the Xcode and the Ninja generators
and runs on Apple Silicon: 144 tests, 141 pass. The three that fail there
(AicaArmTest.LogicOpsTest, SDLControllerMappingTest.split_axis and
.reverse_axis) and an abort in ~maple_sega_vmu at process exit are
pre-existing and are not changed here. The CI workflow still runs the
tests only on Linux.

Co-authored-by: Claude Fable 5.1 <[email protected]>
[ci skip]
2026-10-24 17:24:11 +02:00
Flyinghead 3a498b1cb5 initialize all scheduler ids to -1
[ci skip]
2026-10-24 17:18:03 +02:00
Flyinghead c52e6ccf56 bba: move frame queueing to net services. Call service to rx frame
New Service::sendEthFrame function to send frame to bba
Let net services implement queuing and synchronization
capcom: don't interfere when not in use
2026-10-22 16:32:34 +02:00
Flyinghead de7597f0bc picotcp: fix race condition in enqueue/dequeue 2026-10-22 15:01:18 +02:00
Flyinghead 5f35ec7d72 Merge remote-tracking branch 'origin/master' into dev 2026-10-22 14:13:58 +02:00
Flyinghead fa9d39a355 bba: skip deserialization if device doesn't exist
regression from 5543a95c4f
2026-10-22 12:36:23 +02:00
Flyinghead db065c5700 audio: put the RingBuffer cursors on separate cache lines 2026-10-21 18:24:07 +02:00
Flyinghead 620699865b Merge remote-tracking branch 'origin/master' into dev 2026-10-21 17:47:06 +02:00
Flyinghead a9bd1c74fd empty commit 2026-10-21 17:09:21 +02:00
Flyinghead 5543a95c4f bba: start polling only when needed. Increase poll interval to 1 ms 2026-10-21 16:54:14 +02:00
Flyinghead 78d5d09c1e ci: fix sentry-cli on android builds 2026-10-21 15:59:34 +02:00
Joseph MattielloandClaude Fable 5.1 31697241b7 sdl: initialize the axis direction in SDLControllerMappingParser
SDL_GameControllerButtonBind2 is a struct over a union whose first member
is `int button`. `bind{}` zero-initializes that member only, so
value.axis.direction holds whatever was on the stack. getBindForAxis()
assigns it only when the mapping has a '+' or '-' prefix or a '~'
suffix; for a plain "lefttrigger:a4" it is returned as read, and the
full-axis branch at the end tests it too. At -O2 on macOS/arm64 a
lefttrigger lookup came back with direction 1 instead of 0 and
"-lefty:-a1" with 1 instead of -1; SDLControllerMappingTest.split_axis
and .reverse_axis fail there. The value just happened to be 0 on Linux.

Set axis and direction to 0 before parsing the axis.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-10-21 12:09:24 +02:00
Joe Mattiello e9f4020c56 maplelink: keep the link registry alive through static destruction (#2577)
MapleDevices[][] in maple_if.cpp holds shared_ptr<maple_device>s with
static storage, so the VMUs are destroyed when the process exits.
~maple_sega_vmu() clears the LCD on any attached maple link, which goes
through MapleLink::GetMapleLink() and locks MapleLink::Mutex, another
object with static storage, in another translation unit, that may
already be gone. With libc++ locking a destroyed mutex throws
("mutex lock failed: Invalid argument") and the process aborts; the
unit test binary exits with SIGABRT on macOS after every test passed.
On glibc the same lock happens to succeed, which is why Linux never
showed it. The Links table is read in the same state.

Give both to function-local statics that are allocated once and never
destroyed, so they outlive everything that can still reach them.

Co-authored-by: Claude Fable 5.1 <[email protected]>
[ci skip]
2026-10-21 12:08:48 +02:00
Joe MattielloandClaude Fable 5.1 5eb52090ad arm7: keep the V flag across logical ops in the arm64 recompiler (#2576)
On ARMv7, AND, EOR, ORR, BIC, MOV, MVN, TST and TEQ with the S bit set
leave V unchanged. The AArch64 instructions the recompiler uses for them
(ANDS, BICS, TST) clear V, and storeFlags() wrote the host NZCV back as
is, so every flag-setting logical op cleared the guest's V. A signed
conditional branch (BVS, BGE, BLT, BGT, BLE) after such an op then went
the wrong way. The x64 recompiler already preserves V for these ops
(saveFlags(save_v_flag)); the interpreter does too.
[ci skip]

TST and TEQ had a save/restore under STRICT_MODE with a note that nobody
probably relies on it. That path was never built, and it did not cover
ANDS, EORS, ORRS, BICS, MOVS or MVNS.

Restore V after the op from the PSR that loadFlags() loaded before it,
in the same place the shifter carry is merged, for every logical op that
sets flags. Three instructions, only on those ops.

AicaArmTest.LogicOpsTest asserted exactly this (teq with C,V set must
keep V) and failed on arm64; it passes now, with the rest of the suite.

Co-authored-by: Claude Fable 5.1 <[email protected]>
2026-10-21 12:07:57 +02:00
jutler 128e6ce29c addrspace: mask the shift count taken from the tagged pointer (#2574)
readConst, writeConst, readt and writet shift the 32-bit guest address by
the whole tagged memInfo_ptr value (pointer | shift). Shifting a u32 by 32
or more is undefined, and GCC 16 targeting 32-bit ARM uses that: once the
pointer is known to be non-null (iirf > 31) it drops the offset, so
read32/write16 compile to a plain load/store at the region base. Every
memory access then hits offset 0, the BIOS trampoline copied to 8C0000E0
is lost and the console never boots (black screen, no sound).

Mask the shift with HANDLER_MAX, which is what x86 does in hardware and
what the code intends. No change in behaviour where the old code worked.

Co-authored-by: hitenmandalia <[email protected]>
[ci skip]
2026-10-21 12:07:14 +02:00
Rich Stokes 38a3d83c77 bba: hand Ethernet frames over on the threads that own them (#2569)
Received frames were passed to the RTL8139 from the network thread,
raising the ASIC interrupt there and racing SIIDRebuild() on the SH-4
thread. Queue them and deliver them from an SH-4 scheduler callback.

Sent frames were pushed into picoTCP from the SH-4 thread, but picoTCP
is built without PICO_SUPPORT_MUTEX so its device queue is unlocked.
Queue them and feed them to picoTCP from the pico thread before each
stack tick.
[ci skip]
2026-10-21 12:05:47 +02:00
Joe Mattiello 19ed307f74 rend: rotate sorted triangle indices for flat shading instead of copying colors (#2553)
Vulkan without VK_EXT_provoking_vertex, DX9 and DX11 take flat-shaded
colors from the first vertex, while on Dreamcast it's the last. For the
depth-sorted triangle list, setFirstProvokingVertex() copied each
triangle's last vertex colors onto its first vertex. But sortTriangles()
builds these triangles from strips, so neighbors share vertices:
tri0=(P0,P1,P2), tri1=(P2,P1,P3). P2 is tri0's source and tri1's
destination, and the list is processed in depth order, so one
triangle's flat color can overwrite another's before it's read. In
strips of three or more triangles, consecutive triangles even share
their first vertex. Flat-shaded translucent polygons then pick up a
neighbor's color, e.g. the player shadow decals in Tony Hawk's Pro
Skater 2 and Mat Hoffman's Pro BMX turn uniformly dark.

Each sorted triangle has its own three slots in idx, so rotate them
(a,b,c) -> (c,a,b) instead. The winding is unchanged and the provoking
vertex comes first, without touching shared vertices. Strips keep the
color copy, which is safe there.

Adds SorterTest, which fails on the old code and passes with this change.

Co-authored-by: Claude Opus 5.5 <[email protected]>
[ci skip]
2026-10-21 12:04:35 +02:00
Joe Mattiello d207cd9198 addrspace: clear the address map when its backing memory is freed (#2546)
When nvmem is disabled, termMappings() frees main RAM, VRAM, ARAM and
the Elan RAM but leaves memInfo_ptr unchanged. Each entry still holds
the old host base, so any guest access before the next remap returns a
pointer into freed memory.

Zero the table, as init() does. A null entry routes to handler 0,
readMemNotMapped/writeMemNotMapped, which only log.

Co-authored-by: Claude Opus 5.5 <[email protected]>
[ci skip]
2026-10-21 11:19:28 +02:00
Flyinghead 1d356d5e55 android: fix swappyvk crash if activity is null
[ci skip]
2026-10-21 11:06:06 +02:00
scribam 32c2304459 ci: maintenance updates
- Bump action versions
- Improve ccache support
- Reformat files
- Replace chkfung/android-version-actions and mathieu-bour/setup-sentry-cli from android workflow
- Update MoltenVK to use the latest official tag
- Update BSD operating systems
2026-10-21 10:59:14 +02:00
davey 34ad8c8262 libretro: avoid exporting symbols on linux, android and the bsds
Export only retro_* from the core, as the osx build does with
libretro.osx.def. Symbols the core exports bind to same-named ones
the frontend already loaded: RetroArch builds with their builtin
glslang made the Vulkan renderer crash in GlslangToSpv on its first
shader compile, and with a system glslang loaded (ffmpeg ->
libplacebo -> shaderc) 33 glslang entry points, zstd, zlib and
stb_image still went to those copies.
2026-10-20 16:33:04 +02:00
Chris Dixon abfc411392 libretro: report a fixed savestate size for each system (#2561)
A frontend may size its savestate buffer once, as libretro.h allows,
but a state grows and shrinks with the devices plugged in and the
frames being drawn, and states then outgrow the buffer. Report the
system's memory regions plus the allowance GGPO makes for everything
else, which is constant for a game.

System SP gets NAOMI's allowance, plus the game's media if it has one:
the media is loaded into memory-backed RAM, so a state holds all of it.
[ci skip]
2026-10-20 16:32:32 +02:00