Convert explicit BT.2020 nonconstant-luminance PQ/HLG NV12/P010 into FP16 linear scRGB on the GPU. Use FP16 movie history and a dedicated HDR10/scRGB presentation fragment, preserving absolute luminance and the existing core HDR uniform ABI. The retained backend capability gates HDR activation; unsupported renderer/color combinations retain software fallback. Generic planar texture imports use the same HDR conversion.
Restore history, staging texture, dimensions and movie state if destination allocation or encoder setup refuses an import. Persistent history scratch avoids a history-sized stack allocation. CPU/deferred frames clear movie color state and reinitialize history when leaving HDR.
Validation: complete GCC/Clang portable Metal jobs, final 128 movie and 96 planar mock cases, Windows C89/GDB, 94 workflow selftests, 44-driver thread-state check, complete compile matrix with ARC/MRC Metal rows, final focused Metal rows and scoped native-presentation Objective-C syntax. Native PQ/HLG conversion/history and stock-MSL presentation pixel fixtures are added; actual Apple GPU and full player acceptance remain pending.
Publish the retained Metal device only when the SDR conversion pipeline and shared-event OS gate are available. Withdraw by owner at teardown and retire decoder sessions on a process-lifetime serial dispatch queue. Capability queries remain atomic; hardware settings are checked during decoder setup.
Link CoreMedia and VideoToolbox in the Metal build routes. Annotate HEVC setup availability so older deployment targets can include the guarded startup path. Exercise the shipping bootstrap in the native registered-stream fixture and add a macOS 10.13 compile probe.
Validation: complete GCC/Clang portable Metal jobs, final selected HEVC sanitizer lanes, Windows C89/GDB, 94-workflow selftest, 44-driver thread-state check and complete compile matrix including feature-enabled Metal. Apple SDK/runtime and full player acceptance remain pending.
Protect device publication, setup acquisition and withdrawal with a setup-only registry lock. Retain each snapshot while protected; capability ownership queries remain lock-free and decode/output/retirement never acquire this lock.
Add compare-and-withdraw for HEVC offers and use it in D3D11/Vulkan teardown so an old driver cannot remove a replacement backend. Exercise stale owners, foreign offers and a held snapshot spanning 1000 replacements with concurrent acquisitions; native registered streams now use the registry too.
Fix the Metal compile-matrix regression exposed by broader validation: include the existing dispatch stubs and declare the queue priority and CoreVideo cache factory used by shipping code. Preserve the strict Metal row and native acceptance gates.
The upstream Driver Pacing release and latency-marker dispatch intentionally grows runloop_iterate to 6527 bytes in the menu-harness release build, beyond the old 6255-byte ceiling. Follow the existing budget policy by updating its code-size reference from 5004 to the measured size. Keep the 25 percent margin, stack reference and all other function budgets unchanged. No runloop or pacing behavior changes.
drm, dispmanx, sunxi, omap, exynos and oga draw a core's views, each
laid out on the screen, which every one of them now reports as its
output size, and the viewport is the whole screen while they draw.
The drivers whose display hardware scales a surface to the screen -
drm's plane, dispmanx's element, sunxi's layer and omap's overlay -
compose the views on the CPU at the scale that draws no view larger
than it is, and let that hardware do the enlarging. The composer they
share with xshm is video_views_cpu_compose() in video_views_cpu.h,
which xshm now uses too: each placement cut to its own eye's area,
anaglyph and interlaced through a canvas of both eyes that is then
blended. sunxi and omap at 32 bits compose straight into the page that
is scanned out; omap at 16 bits converts as it goes, and lowers the
scale as far as its overlay's memory needs. drm and dispmanx compose
into a surface of their own, set up beside the frame's and given back
to it when the views end.
The blitters scale each placement straight from the frame: exynos with
the G2D from the GEM buffer the frame is already copied to, oga with
the RGA into an upright surface the size of the screen that one more
blit turns onto the panel, so a turned panel needs no arithmetic of
its own. video_views_cut_source() gives both the part of a view a cut
placement shows. Neither blends eyes: anaglyph, interlaced and, on
oga, a turned core draw the frame whole.
omap's menu buffer now grows with the mode it is scaled to; it stayed
320x240 while a core's larger frame was scaled into it.
The compile matrix builds drm, dispmanx, exynos and oga, against stubs
of the VideoCore userland, libdrm's exynos module and librga where
none of those are installed; libdrm-dev is added to its packages. The
unit test covers the composer and the cut, and the drm harness the
views surface's lifetime and its pixels.
The compile matrix's stubs move into tools/platform_stubs and the
matrix takes them from there. Where both trees had a header, the one
left declares what both sets of users need: ctr/3ds/os.h the clock
and the memory-region queries, ps3/ppu-lv2.h the scalar types and the
lv2syscall1 macro. The libnx stub carries the pad, Joy-Con and rumble
surface switch_joypad.c uses, and samples/input/switch_joypad builds
against it instead of a copy of its own.
Every compile-matrix lane gives the verdict it gave before.
* CI: run the qemu sinc kernel tests side by side
The four NEON sinc tests ran one after another under qemu-user on the
aarch64, aarch64+crc and armv7 legs, five to six minutes a leg, with
the runner's other CPUs idle. Each is one single-threaded qemu
process, so they now run at once, and each one's output is printed
when it is done. A failing test still fails the step.
On CI the step went from 300s to 102s on aarch64, 329s to 169s on
aarch64+crc and 318s to 249s on armv7, where one test alone sets most
of its length.
* tools/tsan-samples.sh: build each suite with every CPU
The suites were built one compile at a time. Built with -j on four
CPUs, the 68 directories in the list took 29s instead of 77s, and none
that builds without -j failed with it. The suites themselves still run
one at a time, so on CI the whole step went from 737s to 622s.
* views e2e: under Wine, each worker gets a prefix of its own
Cases run side by side in one prefix share its wineserver and moved
each other's pointer, so the Wine cases ran one at a time. Each worker
now takes a copy of the prepared prefix, and Wine runs four cases at
once like Xvfb.
On CI the D3D11 and D3D12 cases went from 1457s to 479s, all 120
passing; the pointer cases passed in three more runs on four CPUs.
* CI: one gl harness job per build, and one job for the wait checkers
The gl harness ran as 13 jobs, one per driver, API and sanitizer, but
the build depends only on the API and the sanitizer: each job set up a
runner, installed the same packages and built the same tree as two
others before its one or two minutes of harness. It now runs as 6
jobs, one per build, each running the harness on every driver that
build serves. Every driver runs even when one before it fails.
The three wait and teardown checkers, each under a minute of work,
ran as three jobs; they now share one, every checker running even
when one before it fails.
On CI these 16 jobs became 7, and 27.1 runner-minutes became 24.5.
* CI: MSYS2 installs Qt's base package only
The MSYS2 lanes installed about 40 Qt 6 modules, though configure
reports Qt support disabled on all four of them, so none of it is
built.
qt6-base still brings in the libraries configure does find (FFmpeg,
SDL2, FreeType, fontconfig, libass, glslang, SPIRV-Tools, OpenSSL).
The MinGW packages fetched drop from 198 (597MiB) to 152 (319MiB). On
CI the install steps of the four lanes went from 772s to 523s, and
configure found the same libraries on each.
* CI: sanitizer and debug builds of the tree use -g1
The samples moved to -g1 in 21635dd1, but every DEBUG=1 build of the
tree still took the Makefile's -O0 -g: the gl and Vulkan harness
sanitizer builds, pace-shadow, the TSan harness, the autoconf
sanitizer matrix and the C89 debug build. A sanitizer report needs
only line tables, which -g1 keeps.
Those jobs now set CFLAGS and CXXFLAGS to -O0 -g1 in the environment.
Where configure sees them it writes them into config.mk, and where
only make does, the Makefile's CFLAGS ?= takes them; either way they
replace DEBUG=1's -O0 -g and the Makefile's own flags are still
added, which they would not be from make's command line. The
threaded-video harness takes its compile line from the tree's, so its
run step sets the same. The one-off -O1 -g test compiles in the
workflows and the companion test scripts use -g1 as well. The Makefile
default is unchanged for local debug builds.
The ASan+UBSan DEBUG=1 build, from an empty cache on four CPUs here:
ccache 83MB -> 55MB, objects 530MB -> 424MB, 84s -> 80s. The gl
harness passed on that build, and an ASan report from a -g1 binary
still names the file and line.
* CI: print ccache's statistics in every job that keeps a cache
Only 7 of the 34 jobs that restore a ccache printed its statistics, so
for the rest a cold or missed cache was invisible. Each now prints
ccache -sv before saving, including the direct and preprocessed hit
counts, and a failure to print does not fail the job.
* Makefile, Makefile.webos: GIT_VERSION for version_git.c only
-DGIT_VERSION=<hash> went on every file's command line. ccache's direct
mode hashes the command line, so each new commit missed it for every
file, and CI's restored caches only ever hit after running the
preprocessor again: about 2.5% of hits were direct. Only version_git.c
reads the macro; the rest test HAVE_GIT_VERSION, which stays global.
Makefile.webos has its own compile rules and gets the same change.
On CI, with the cache of the commit before, the ASan+UBSan build had
418 of 418 hits direct.
* CI: the cross-arch ccache keys name their architecture
The retro-atomic-cross and crc32-cross legs shared one cache key per
commit, so only one leg's cache was saved ("Unable to reserve cache
... another job may be creating this cache") and the next run's legs
all restored whichever architecture won. Each leg now saves its own.
* CI: prune superseded ccache entries
Master pushes save each job's ccache under a key ending in the commit,
and only the newest per job is ever restored. Upstream's 10GB store
held 256 entries: 61 newest-per-job (4.24GB), 195 superseded (6.46GB),
and 2.3GB of other caches. Least recently used went first, so the
newest cache of a workflow that had not run for about four hours was
gone by its next run, which then built cold.
A workflow on each master push and hourly deletes every ccache entry
keyed on a commit that a newer one of the same job on the same branch
replaces. Other caches are left to GitHub's own eviction.
* CI: MXE builds keep a ccache
The two MXE cross builds compiled RetroArch from nothing on every run.
Their images ship ccache, so they now restore and save one like the
Linux jobs, with the compilers wrapped at configure time.
On CI, with the cache of the commit before, the compile went from 154s
to 18s on x64 and 166s to 11s on i686. A run with no cache at all is
slower than before, about 250s, as is any first build through ccache.
* CI: console builds keep a ccache
Switch, PS Vita, Wii, GameCube, DOS and the macOS PowerPC cross builds
compiled every file on every run. Their images run actions/cache but
ship no ccache, so the job installs it, and a small script reads CC
and CXX from the platform Makefile with the job's own variables and
runs make with both wrapped. The PowerPC legs each keep a cache of
their own. As in the Linux jobs, the cache is capped at 250MB, its
statistics are zeroed after the restore, and it is saved on master
pushes only. Installing ccache is retried and best effort: without it
the script runs plain make. The PS Vita and Wii Salamander builds,
which run first, are left as they were.
On CI, with the cache of the commit before:
PS Vita 120s -> 4s Switch 84s -> 2s
Wii 50s -> 9s GameCube 44s -> 9s
DOS 49s -> 4s macOS PowerPC 116s -> 2s
With no cache at all most took 5-30s longer than before; PS Vita took
148s longer.
PS2, RS90 and RetroFW are left out: their compiles did not go through
ccache this way. Miyoo is too: it hit every compile but went only from
50s to 38s, about what installing ccache costs.
* CI: webOS builds keep a ccache
The webOS job builds three configurations with make clean between
them, each from nothing. It now sets up ccache and wraps the compilers
like the console jobs.
On CI, with the cache of the commit before and before Makefile.webos
kept the commit hash to version_git.c, the three compiles went from
110s to 53s.
lld ships with the runner image under a versioned name. A step after
checkout in each ubuntu job (83 jobs; container jobs are left alone)
runs .github/workflows/scripts/use-lld.sh, which finds it and puts a
small "ld" first on PATH that the host gcc then links with. Cross
compilers keep their own prefixed linkers and clang its own.
GNU ld still does the links lld cannot stand in for: any link with
--wrap (lld also wraps calls inside the defining object, which the
wrapping samples do not expect), and gcc -flto objects, which lld
cannot read - those fail under lld and are run again with GNU ld.
No lld on the runner leaves the job on GNU ld.
RetroArch's link here: 1.6s with GNU ld, 0.9-1.2s with lld. The
samples that wrap, use -flto, --gc-sections or -Map build and pass
their checks through it.
The platform makefile and console object checks captured their status
after a plain command substitution, which under set -e ends the script
on the first failure before the status is read: no FAIL line, exit 1,
and every lane after it - the video drivers, the gates, the unity
build - never run. A host missing one package the checks compile
against made the whole matrix look run when two thirds of it had not.
The status is now taken in the same list as the substitution, so the
check prints its FAIL and the lanes after it run.
* menu: the cursor stays on Headset Output when Stereo Mode comes and goes
Stereo 3D & Screens lists Stereo Mode above Headset Output only while
the headset is off. Turning it on moved Headset Output up a row and
left the cursor on the row below it, Headset Refresh Rate, so a second
OK meant to turn the headset off opened the rate list instead.
The cursor follows the row, as it does for Mapped Port when Device Type
comes and goes. samples/menu/stereo_headset checks it for OK, right
and Start.
Co-authored-by: Craig <[email protected]>
* openxr: a session without focus is not logged as controllers not read
xrSyncActions answers XR_SESSION_NOT_FOCUSED, a success code, while the
runtime's dashboard or another application has focus. It was logged as
a warning each time focus went; only a failure is now.
The test layer answers a sync with a scripted result (sync <n>), and
the headset suite gains input-sync-unfocused.
Co-authored-by: Craig <[email protected]>
* libretro: a TRACKED view map, and HMD is how a core finds a headset
A map's shape could not tell a head-tracked eye pair from a
stereoscopic screen sent alone. The new flag says which. HMD now means
tracking works, and a core learns of a headset from it only.
REQUEST_FLAT is a map without the flag, and OpenXR always gives real
eye poses, so the flag and the IPD hint go; nothing read either.
Co-authored-by: Craig <[email protected]>
* openxr: the runtime, session, swapchains and frame loop are shared units
The desktop Vulkan host's instance and headset, its session state
machine, its swapchain slots and its frame loop with pacing move into
gfx/common/openxr_*, which name no graphics API, so every headset host
can use them. vulkan_openxr keeps only what is Vulkan's.
Co-authored-by: Craig <[email protected]>
* video: the headset's host says how it is, and answers the pose calls
One host interface reports the headset's state on the desktop and the
Quest alike. HMD comes with PRESENTS and STEREO, and only while the
session runs. The pose calls go to the host, and a view map sent again
unchanged is not applied again.
Co-authored-by: Craig <[email protected]>
* openxr: a TRACKED map's eyes are the desktop headset's projection
Tracked content gets a space of its own, LOCAL or STAGE as the core
asks, and the poses sampled in it. The eyes the core draws are
submitted as a projection layer with the poses it was given, and the
screens a headset leaves to that projection are hidden. A recenter
moves a seated world with the screens; a standing one stays where the
room puts it, and the core is told RECENTERED. A paused core's tracked
world comes back after a driver reinit. The views test core can draw a
world-locked grid, for checks made in a headset.
Co-authored-by: Craig <[email protected]>
* vulkan: the Quest's headset runs on the shared OpenXR core
The runtime starts Android's loader and tells the instance of it. A
headset frame can be begun and ended inside the video frame, so
vulkan_openxr runs in-line for a headset's own context, which says so
in its flags. The units that name no graphics API build without Vulkan,
and a GLES binding is ready for the GL host. A space a core asks for
again is kept, so a cached context keeps its paused world.
Co-authored-by: Craig <[email protected]>
* gl: the Quest's headset runs on the shared OpenXR core
The Quest's ES3 context is its own in-line host: gl2 draws into a
window the context owns, shown as a screen in the room, and copies a
tracked map's eyes into the headset's projection. The window shows
until the first projection. The kept view pair lives in openxr_host, so
the GL host keeps a paused world across a reinit as Vulkan does. The
quest flavour builds with GLES=3. A stand-in runtime test runs the
in-line host.
Co-authored-by: Craig <[email protected]>
* input: one headset controller module for the desktop and the Quest
The headset input's hooks belong to the frame, so any host attaches the
module, and the Quest's own controller module goes. Touch's menu button
is Start from its press, and opens the RetroArch menu when let go after
a second. The menu's laser can point at a window shown whole, mapped
through the area the core is drawn in. The stand-in test runs the
shared module.
Co-authored-by: Craig <[email protected]>
* video: headset settings for every headset driver, and Screen Placement
The headset's rows show for every driver with a headset path. Recenter
works in the menu and reaches the Quest's GL host, and a seated
recenter moves a paused world with the screens in the same headset
frame. Screens are placed from an anchor of their own: Fixed in Room,
Follow Head or Lazy Follow. The Quest asks for a refresh rate that fits
the content and repeats each core frame for whole headset frames.
Co-authored-by: Craig <[email protected]>
* input: the headset's controllers are a controller
They take joypad slots with built-in profiles, so hotkeys, port binds,
remaps and rumble use the normal input path on the desktop and the
Quest. They take the next free slot like any pad, and keep their port
when a gamepad is plugged in, without saving that exchange. A saved
"Meta Quest Touch Plus Controller" profile and its remaps no longer
apply.
Co-authored-by: Craig <[email protected]>
* gl: headset output for the desktop OpenGL drivers
glcore and gl show a headset on Linux. The XR thread holds a context in
the window's share group, made by the X11, X11 EGL and Wayland context
drivers, and the session binds it through XR_KHR_opengl_enable or
XR_MNDX_egl_enable. The video thread draws each image into shared
textures and hands it over with a fence through a triple buffer; the XR
thread copies the newest into the swapchain and shows it with the quads
or the eye poses it was drawn with. glcore draws the screens and the menu
through chains of its own and a tracked map's eyes as the projection, as
Vulkan does. gl shows its window, whole or cut into an untracked map's
screens, as the Quest does, and tracked eyes as the projection. Both
follow the headset's pacing: the XR thread wakes the core for its next
frame after taking the last, so none is shown a headset frame early.
OpenXR configures with OpenGL alone, without Vulkan. The test layer
captures OpenGL swapchain images, and the headset end-to-end runner has
lanes for both drivers on GLX and EGL.
Co-authored-by: Craig <[email protected]>
* docs: OpenXR headset output, and how a headset or graphics API is added
What the headset path does and how to build and turn it on, what a core
sees, which units are shared and what each of the three hosts adds, and
the steps for another headset, graphics API or platform.
Co-authored-by: Craig <[email protected]>
* audio: pass the reinit flag to MMDevice watchers
XAudio2 and DirectSound must give mmdevice_thread the frontend atomic flag. Passing the driver object overwrites its watcher handle when an endpoint changes. Exercise both thread backends against the extracted production spawn functions.
* test: reject video backend fallback in the threaded harness
Fail early when HARNESS_VIDEO_DRIVER differs from the initialized backend so a missing driver cannot qualify another backend's lanes.
* Animated previews: keep high-bitrate audio fed across loops
Size the audio lookahead from the preview bitrate, prime it before playback, and refill the full window on rewind. The audio demuxer walks interleaved video packets too; a fixed 2 MiB window stalled on large H.264 packets and left high-bitrate previews silent or delayed after looping.
Add a real feeder/mixer regression using generated oversized video packets. Verify that audio continues through three complete loops; the previous feeder fails this test. Validate both reported 4K clips locally on Windows and Linux.
* wdmks: bound threaded writes by the device fragment
A small write can exhaust its request-sized wait budget before a healthy WaveRT pin's next notification. Size the threaded ring waits from rt_ahead instead, and cover writable waits and blocking writes against a 64 ms fragment.
* CI: views end to end on glcore and Vulkan under Xvfb
run.py gains RA_E2E_XVFB (Xvfb in place of gamescope, llvmpipe and
lavapipe) and RA_E2E_ONLY (a case filter). The validation job runs a
subset of the cases.
* Views: one compositor for gl3 and Vulkan
gfx/video_views_draw.h holds the chain pick, the placement loop with
the interlaced row shift, and the canvas and UI target lifetime. Each
driver includes it with its own calls bound in by macros, so nothing
goes through a function pointer. The UI layer's predicate, per-eye
test and dims swap move to video_views.h. Output is unchanged.
* Threaded video harness: the frame on screen is the core's newest
A frame lag lane checks, end to end, that what the driver draws is the
frame the core pushed last: the harness core stamps each frame with its
number in eight full-height bands that survive scaling and filtering,
and the lane reads back the driver's own upload (the cached frame
dropped first) and decodes it. Copied, lent and lent as a cropped
window, with threaded video off and on: with nothing in flight it must
be the newest pushed frame, and with frames still in the wrapper's ring
at most one behind. A zero-copy path that draws a buffer the core has
since rewritten, or skips an upload, or a wrapper that holds frames
back, fails it.
It runs on vulkan, gl and glcore, desktop and GLES 3, in the existing
harness jobs (release, ASan+UBSan, TSan, the validation layer).
* Fix MSVC preprocessing of video views UI checks
Move widget conditionals outside VIDEO_VIEWS_UI_WANTED calls in the GL3 and Vulkan drivers. The traditional MSVC preprocessor treats directives inside macro arguments as tokens, breaking the Windows build.
* Provide audio state in the DirectSound pump harness
The device notification thread now uses the audio state reinit request. Supply a persistent harness-owned state through audio_state_get_ptr so the standalone MinGW test links.
* Preserve RetroArch when building the threaded video harness
Request the link command with make -W instead of deleting the frontend executables. The later video views end-to-end tests need the existing RetroArch binary to launch.
* ATRAC3plus: accept implicit master code-table indices
Master channel code-table mode 3 has no payload and uses zero indices. Return before consuming the optional value count bit, rather than rejecting valid frames and losing bit alignment. Add a synthetic regression covering float, s16 and reset decoding.
* Expose hardware H.264 decoding with CPU planes to cores
Provide an experimental versioned frontend decoder interface with Vulkan and D3D11 I420 readback. Reserve private video queues through Vulkan device negotiation v2, and retain the decoder backend with cached devices across video driver reinitialization. Keep software fallback for unavailable or disabled hardware decoding and cover readback in decoder and GPU tests.
* ATRAC3plus: distinguish coded and declared subband flags
Use coded subbands for stereo swap and negation flags and declared subbands for window shapes. Add a synthetic audible stereo regression to detect parser misalignment when fewer subbands carry spectra.
* D3D11: views
The driver draws a core's views through video_views_draw.h, straight
from the frame as the stock chain draws it: placed in each eye's area,
blended through a canvas for anaglyph and interlaced, with the UI drawn
once into a layer composited into each eye. With a preset or HDR output
the frame is drawn whole.
Windows-wine-views.yml runs the views end to end on it: run.py gains
RA_E2E_WINE, for retroarch.exe under Wine with vkd3d's shader compiler,
and the test core builds as a DLL.
* D3D12: stock pipes made for the swap chain's format
The pipes were made before the swap chain, whose formats were still
unset, so every stock draw had an UNKNOWN target format: Windows drivers
draw it anyway, vkd3d (Wine) draws nothing. They are made after it now.
* D3D12: views
The driver draws a core's views through video_views_draw.h as the
D3D11 driver does: straight from the frame, through a canvas for
anaglyph and interlaced, with the UI drawn once into a layer composited
into each eye. Its SDR pipes keep coverage in alpha, which the layer is
composited by. With a preset or HDR output the frame is drawn whole.
Windows-wine-views.yml runs the views end to end on it as well, on
Wine's vkd3d over lavapipe.
* openxr: apply unified headset support to current master
Apply PR #19811 at 3d4ad57 to master at 204f03cfec, resolving its
conflicts with the shared views compositor and hardware video decoder.
Retain master's compositor and GL frame-memory interfaces while
preserving the PR's headset UI sizing, shader-chain cleanup, tracking
and controller support. Keep both sets of regression tests and the
hardware decoder callbacks alongside the OpenXR pose helper.
---------
Co-authored-by: Craig <[email protected]>
Co-authored-by: Codex <[email protected]>
Co-authored-by: libretroadmin <[email protected]>
The D3D11 video backend's frames, opened on the D3D12 device through
the same NT handles: the shared NV12 texture as two plane views, the
fences as ID3D12Fences. Each frame converts in a command list of its
own, executed at once on the driver's queue behind the decoder's fence
and signalling the reader's, so nothing waits on the CPU; with all four
lists still in flight the frame is dropped. They signal a fence of
their own, as a signal on the queue fence between a frame's recording
and its execution would take the value that frame's resources wait for.
The backend starts on the D3D12 driver's adapter and loads d3d11.dll
itself. The GPU oracle in samples/gfx/d3d11_video_decode now reads
every stream through D3D12 as well, where there is a device.
rh264's hardware backend on D3D11 video (DXVA), as the Vulkan one is
on Vulkan Video. Each decoder has a device of its own on the driver's
adapter, so the driver's device stays on its own thread. A picture to
be shown is copied into a shared NV12 texture behind a shared fence;
the driver opens both by their NT handles, waits on the GPU, converts
with the planar compute shader and raises the texture's own fence.
Needs Windows 10 1703 and NV12 sharing; anything less, or a stream
the GPU will not take, decodes on the CPU as before.
The DXVA buffers are written byte by byte (gfx/common/dxva_h264.h), so
no dxva.h is needed. samples/gfx/d3d11_video_decode checks them against
one, runs the backend on a D3D11 that records what it is told, and has
an oracle that compares a GPU's frames with software's.
gfx_surface_player is video_player with a gfx_surface as its sink:
frames are decoded into the surface's slots and submitted from there,
a frame the driver dropped is sent again when the slot comes back,
and the surface stays the consumer's. Animated thumbnails play through
it as before, with their window feed and preview audio left where
they were; the desktop companions' preview thread drives a player in
line and scales from its canvas; looping overlay images play through
one each, still looping whatever the file's count says.
The companions and overlays gain the shared pacing: durations kept
to the file's rate instead of reset per frame, and catch-up when the
decode falls behind. overlay_apng now plays the fixture the way the
overlay does, and a new on-screen lane runs an animated overlay in
the real binary, threaded and not.
Both GL drivers now answer TEXTURE_GPU_FORMAT_YUV420 and convert planar
frames themselves, through one converter they share in gl_common
(gl_planar_*): the planes go up from where they lie into R8/RG8 - or
luminance and luminance-alpha where the context has no core profile -
row lengths covering any stride, a row at a time on GLES2 only, and a
fragment shader draws them into the RGBA texture the frontend is
handed. It samples the chroma a 2x2 block shares, so the result is the
CPU conversion's at any size, either chroma order. The driver's state
is put back as it was, and a program that will not build turns the
format off rather than failing every load.
The harness's planar lane holds gl and glcore to the CPU conversion as
it does Vulkan, and the compile matrix builds the converter for GLES2
and GLES3.
With the allocating loader gone, video_thread_async_deliver is small
enough that GCC inlines it into video_thread_frame, which runs it every
frame anyway: the call is gone and the frame is 56 bytes larger, two
past a budget measured from a reference the function had long outgrown.
The reference moves to what the frame measures now.
Both standalone camera lanes supply their Android feature defines explicitly. Do not require config.h, which a clean checkout does not contain and which would import unrelated host features into these target checks.
Declare size_t directly instead of relying on a platform header to provide it. Add a PS2-profile C89 check to the compile matrix so the missing include cannot pass desktop-only coverage.
Both drivers front the device with a ring their own thread drains -
WDM-KS's refill thread into the mapped WaveRT loop, Pulse's server
thread into the stream - so both now lend the span at that ring's
head through write_begin/write_end, as WASAPI does, and the threaded
pipeline produces its output there instead of copying it in. A
WDM-KS integer pin is fed float of the same size, so its lent span
is converted in place on publish, which also retires the separate
conversion buffer's copy. Paused or not-ready Pulse streams, WDM-KS
packet pins, the AC-3 path and builds without threads keep write().
wdmks.c did not build without threads: the loop geometry it needs at
init sat inside the refill thread's guard. It is outside it now, and
compile-matrix builds the driver in that shape. wdmks_loop checks the
lend against the loop, the in-place conversion and every refusal;
live_drivers lends against a live Pulse server with the mainloop lock
counted.
RETRO_CAMERA_BUFFER_PLANAR hands a core the capture device's own 4:2:0
planes, untouched, for the duration of the callback; the frame
callback sits past the end of retro_camera_callback and is read only
when its caps bit is set, so older cores are never read past.
The Android driver picks the cheapest delivery the core accepts: the
SurfaceTexture for a GL hardware context, the planes for a planar
core, and XRGB8888 converted once by image_yuv_blit only for a core
that takes nothing else. Planes come from Camera2 through the NDK
(resolved at runtime, the HAL buffer mapped where it lies) and fall
back to the legacy Camera's NV21 preview buffers, rotated between the
camera and the reader without a copy. No permission is declared: a
port that declares CAMERA gets the prompt, others get no camera.
Both drivers load, update and unload textures: a texture is its
texels tiled as GX RGBA8 into memory of its own, which the GPU samples
where it lies. An update tiles the new texels over the old - the GPU
has finished drawing by the time a frame returns, so nothing reads
them meanwhile. image_texture_tile_gx_copy() does the tiling into a
separate buffer, padding a side that is not a multiple of 4 instead of
cutting it.
The overlay pack is shown as those textures (load_textures), so it is
tiled once, kept across the overlay cache and freed from the CPU, and
an animated overlay plays. A pack is no longer tiled as it decodes and
the surface requirements on GEKKO are the common ones; a page shown
through load() is tiled into the overlay's own memory. gx's overlay
filter is set on the overlay's texture, not the core frame's. CI
compiles gekko_gfx.c, and both drivers' overlay code.
RetroArch_iOS6.xcodeproj builds for armv7 at a 6.0 deployment target
against the iOS 9.3 SDK, and everything newer than iOS 6 that it
called directly is now behind a runtime check:
- CADisplayLink's rate goes through cocoa_display_link_set_rate() and
cocoa_display_link_get_rate(): the frame-rate range from iOS 15,
preferredFramesPerSecond from iOS 10, frameInterval before that.
maximumFramesPerSecond, nativeBounds and safeAreaInsets are selector
sends behind their versions.
- The document picker, size transitions and openRetroArchURL: are
annotated API_AVAILABLE and reached through iOS 8 checks; the
library reply opens through openURL:options:completionHandler: from
iOS 10 and openURL: before it.
- UISelectionFeedbackGenerator, the alternate icons, layout anchors,
the smart-text traits and base64 encoding go by selector and class
lookup; containsString: gives way to rangeOfString:.
- MetricKit, scenes, pointer interactions and CoreHaptics declare types
the 9.3 SDK does not have, so those stay behind SDK gates.
apple_runtime.h supplies API_AVAILABLE on SDKs older than iOS 11 as
clang's availability attribute, so annotated methods are checked there
too. verbosity.c includes os/log.h on the same condition as its call,
gl2.c's macOS FBO extension path no longer takes iOS SDKs that also
define the macOS version macro, mem_stats.c reads
limit_bytes_remaining only where task_vm_info has it, and PRI_SIZET is
"lu" on Apple.
OpenAL is deprecated from macOS 10.15 / iOS 13 but present on every
release; openal.c defines the headers' marker empty, as the GL headers
take GL_SILENCE_DEPRECATION. features_cpu.c declares the affinity
array only where it is filled, and the tvOS display server no longer
keeps a screen it does not use.
The new "CI iOS 6 (armv7)" workflow fetches only the 9.3 SDK's headers
and runs .github/workflows/scripts/ios-legacy-check.sh, which compiles
griffin_objc.m (ARC) and griffin.c with the iOS 6 project's own
defines at a 6.0 floor and treats every warning as an error, so an
unguarded newer API fails the job.
The three drivers answer update_texture, so a streaming surface - an
animated thumbnail, an APNG overlay - keeps one texture and rewrites it
each frame instead of creating and releasing one. D3D8 and D3D9 lock
level 0 of the managed-pool texture their load made, which writes the
runtime's system copy without waiting on the GPU. D3D10 maps the staging
texture its load made with DO_NOT_WAIT and copies it across, dropping
the frame rather than stalling when the GPU still has the last one.
D3D8's texture load and unload reach the video thread wrapper only
under HAVE_THREADS, as every other driver's do, so a build without
threads links. The compile matrix builds every D3D driver without
threads as well, where a wrapper call outside HAVE_THREADS shows up as
the implicit declaration it is.
Makefile.wii, Makefile.wii.salamander and Makefile.ngc build on
RetroArch's own system layer, os/gekko. HAVE_LIBOGC=1 still builds the
_libogc drivers, always against devkitPro's libogc and libfat; the copy
of libogc under wii/libogc, the build of it (Makefile.libogc) and the
libsysbase bridge it needed are gone, and with them EXTERNAL_LIBOGC and
GX_PTHREAD_LEGACY. The Wii and GameCube workflows build the default.
b2968a37 gave the message pump a branch for when the raw input driver
reads by its poll: it takes everything below WM_INPUT and everything
above it. Where there is no raw input driver the branch was switched
off with a macro that expands to false, which still compiles it, and
the MSVC 2005 job builds for _WIN32_WINNT 0x0400 with an SDK that has
no WM_INPUT at that level:
ui/drivers/ui_win32.c(160) : error C2065: 'WM_INPUT' : undeclared
identifier
The branch is under the same condition as the driver now.
Nothing on GitHub could see this: mingw-w64 declares WM_INPUT whatever
_WIN32_WINNT is. The compile matrix has "win32-old" lanes that build
ui_win32.c and win32_common.c for 0x0400 behind a header that takes
those names away again, as that SDK does. The ui_win32 lane fails with
the same error before this change and passes after.
Not built with MSVC 2005 here. That was the only error cl reported for
the unit, and the other files that name WM_INPUT are not built below
0x0501.
9b9b659e put keyboard events from another thread on a lane the poll
takes, and input_keyboard_event() - compiled either way - ends by
calling input_keyboard_event_now(), which is defined after it. The
forward declaration sat inside the lane's HAVE_THREADS block, and the
one meant for a build without threads came after the call. Emscripten
is the job that builds this file without threads:
input/input_driver.c:10153:4: error: call to undeclared function
'input_keyboard_event_now'
input/input_driver.c:10157:13: error: static declaration of
'input_keyboard_event_now' follows non-static declaration
One declaration, ahead of the HAVE_THREADS block, replaces both.
The compile matrix had no lane for input_driver.c without threads, so
only the Emscripten build could see this. It has one now: it fails
with those two errors before this change and passes after.
Also compiled with clang and the Emscripten job's defines, the
Emscripten-only ones aside: two errors before, none after. Not built
with emcc here.
The compile matrix builds the three drivers together the way griffin
does for the MSVC and Xcode builds, so a file-scope name two of them
share is a failure here rather than on those builds.
compile-matrix.sh's GameCube and Wii driver lanes take libogc's headers
from devkitPro's libogc at v3.1.0, fetched on first use (LIBOGC_DIR
names a checkout to use instead), rather than from the in-tree copy,
which is going away. They build as the external-libogc builds do,
with EXTERNAL_LIBOGC, and the GameCube lane names its platform, which
libogc's headers require.
The GameCube and Wii units built on libogc take a _libogc suffix:
platform_gx, platform_wii, gx_gfx, gx_gfx_vi_encoder, dispserv_gx,
gx_audio, gx_joypad, wiiusb_hid and mem2_manager. Their drivers keep
their idents, so configurations carry over. Native drivers on os/gekko
come in beside them under their own names.
OpenVG draws on-screen messages again, through the shared glyph cache
and gfx/font_layout.h: the A8 atlas is one VGImage, uploaded where it
is dirty and made again when it grows, and each glyph is a child image
of its rectangle drawn multiplied by the message colour, drop shadow,
alignment, line spacing and scale as the other drivers draw them.
SDL2's own OSD message walks the text through the same layout and
remakes its texture when the atlas has glyphs it does not, and GX
decodes the message as UTF-8 into its bitmap font, drawing what that
font lacks as '?'. The glyph cache reads its frame counter relaxed, a
plain load on every backend; it is only compared.
The OpenVG stub carries the Khronos prototypes and values, so the
compile matrix checks vg.c's calls, and a GameCube lane builds GX's
SRAM branch. samples/gfx/font_lifecycle gains vg and sdl2: the
shipping drivers draw messages, OpenVG onto a software OpenVG and SDL2
through its software renderer, and every glyph texel is checked where
it lands.
The three hex_byte buffers in the HMAC and signature code take their
two digits by assignment; C89 only allows constant initialisers in an
aggregate. The compile matrix holds s3.c to the full C89 lane, since
no build compiles it in C89 otherwise.
The ubuntu-24.04 image's GCC lays runloop_iterate out at 5004 bytes
for the same source the reference was taken from; the reference is
that measurement, so the budget is again a quarter over it.
font_driver_resolve_params() fills in what a video driver's font draws
a message with: the caller's font_params, or for the on-screen message
the position and colour from the settings, left aligned, full screen,
opaque, under the usual 2 px shadow at 0.3 of the colour - with the
colour both as floats and as bytes, and the caller's float colour passed
through. Every video driver that drew from font_params resolves them
there instead of copying them field by field and reading the settings
itself; what is each driver's own stays with it - its packed colour
layout, the "alpha 0 means opaque" fix-up where it had one, and the 3DS
and PS2 drivers' own shadow for the message - and every driver ends up
with the same values as before. SDL2's and the Switch's on-screen
message take its position, and SDL2 its colour and shadow, from the
settings as the others do, where both drew it at the screen's corner.
The compile matrix's clang font layout lanes reject a declaration after
a statement, apart from the PS2 and Wii U drivers' C99 toolchains.
The GDI driver's font lays text out through gfx/font_layout.h, which
leaves no video driver with a text layout of its own. The layout block
splits the message into lines and hands each one over, through
FONT_LAYOUT_SKIP, to be drawn as its shadow run and then its text run,
so the text still lands on the shadow; a run walks its glyphs through
the block too. Untinted text is AlphaBlended a glyph at a time as
before, and tinted text baked into the scratch DIB and blitted per line;
a tinted line that is also right or centred is measured once rather than
twice. The Windows 95 path, which hands the line to TextOut, is as it
was, and the calls into GDI and the scratch contents are the same as
before.
The layout block documents fl_m, the current line's first byte, as
readable from its hooks, which is how a driver drawing a line in passes
of its own gets the line. The compile matrix's clang font layout lanes
cover GDI.
The software drivers that blit their own on-screen messages walked them
a byte at a time, so a multi-byte character came out as one Latin-1
glyph per byte - nothing a fallback font could help with - and a line
break was looked up as a glyph. They lay messages out through
gfx/font_layout.h instead: UTF-8, a codepoint the font cannot draw shown
as '?', and each line one line height below the last. Each blit is
unchanged; a glyph left out at the screen's edge now advances the pen,
where the next one used to be drawn in its place.
The OGA driver hung on a codepoint its font had no glyph for, never
stepping past it, and wrote past its message surface once the text
filled it. It wraps a glyph before it would cross the right edge, draws
nothing once a row would cross the bottom, and reports no more height
than the surface has.
The Metal driver's font lays text out through gfx/font_layout.h, one
method where it had a per-line method, a wrapper splitting the lines and
a width method called per line for right and centred text. It keeps its
pixel-snapped line origin, its six-vertex quads in the vertex range and
its atlas-cell update after every glyph lookup, the measuring pass's and
the '?' stand-in's included. The message length is passed down rather
than rescanned, and the vertices and cell updates are the same as before.
tools/platform_stubs/metal stands in for the parts of the macOS SDK the
driver uses - Foundation, AppKit, Metal, MetalKit, QuartzCore, simd - in
the shapes the SDK gives them, and the compile matrix compiles
gfx/drivers/metal.m as Objective-C against them with clang. A selector
the stand-ins do not declare is an error there, so a new Metal call
needs its declaration added with it.
The SDL3 driver's font lays text out through gfx/font_layout.h, as SDL2's
does: one function where it had a per-line function and a wrapper
splitting the lines, keeping its top-left pixel origin, floating-point
pen, atlas upload at the start of each line and SDL_RenderGeometry
batches of up to 64 glyphs on the stack. A right or centred line is
measured in the layout's own pass rather than by its width function,
with the '?' stand-in known before it, and the vertices and draws are
the same as before.
The compile matrix's clang font layout lanes cover it where the SDL3
headers are installed.
Both D3D9 drivers' fonts lay text out through gfx/font_layout.h. Each
looks a glyph up once for a line's shadow run and its foreground run,
drawn in that order as before, where it used to measure and walk the
line again for each run, and the draw both runs repeated is a function
of its own. Empty lines are passed over before any lookup, as they were.
The vertices and draws are the same as before.
The compile matrix's clang font layout lanes cover both.
The lane compiled gfx/drivers/vulkan.c against the system's
<vulkan/vulkan.h>, which the runner does not have, and failed there. It
now takes the Khronos headers the tree carries in gfx/include, as the
real builds do, and runs on any runner.
The 3DS, PS3 and D3D8 drivers' fonts lay text out through
gfx/font_layout.h. The 3DS keeps its vertex cache, its capacity check
ahead of each line and its per-line draw, now a function of its own; the
PS3 keeps its integer line origin, six-vertex quads and 64-glyph chunked
draws. D3D8 looks each glyph up once for a line's shadow run and its
foreground run, drawn in that order as before, where it used to measure
and walk the line again for each; its scissor cull now runs before the
line is measured, so a line out of view is not looked up at all. All
three produce the same vertices and draws as before.
The layout block takes an optional FONT_LAYOUT_SKIP, for a driver that
can tell a line will not be drawn before looking any of it up. The
compile matrix's clang font layout lanes cover D3D8.
The PS2, Switch, Vita and Wii U drivers' fonts lay text out through
gfx/font_layout.h, one function where each had a per-line function and a
wrapper splitting the lines. Each keeps its own line origin and the way
it draws a glyph: PS2 its per-line alpha state and gsKit sprites, the
Vita its atlas copy and tinted draws, the Wii U its vertex cache, its
truncating pen and its per-line draw and capacity check, the Switch its
software blit and its line-length limit. The text length is passed down
rather than rescanned.
The Switch blit counted rows with the line's own y origin, so every glyph
after the first on a line was drawn at the height the previous one ended
on; it has counters of its own. The compile matrix's clang font layout
lanes cover the four, and the Vita driver no longer leaves its shader
patcher's result set but unread.
The GL1 and SDL2 drivers' fonts lay text out through gfx/font_layout.h,
one function where each had a per-line function and a wrapper splitting
the lines: GL1 keeps its integer line origin, six-vertex quads and
64-glyph chunked draws; SDL2 keeps its top-left pixel origin, its
floating-point pen, its atlas upload at the start of each line and its
SDL_RenderGeometry batches. The text length is passed down rather than
rescanned, SDL2 measures a right or centred line in the layout's own pass
instead of calling its width function per line, and both draw the same
pixels as before.
The compile matrix's clang font layout lanes cover both.
D3D10 measures a line with a shadow or an alignment first, then writes
each glyph once as its shadow and its foreground sprite, straight to
their slots - the line's shadows ahead of its glyphs, as before - where
it used to measure and walk the line again for each of the two. D3D12
keeps its single interleaved pass and its retroactive shift of right and
centred lines; the line splitting, glyph lookup and '?' stand-in are the
shared block's. Both keep their own truncating pens and their rule for
lines too long for the buffer, and write the same sprites as before.
The compile matrix's clang font layout lanes cover both.
A driver that draws through gfx/font_layout.h but has no use for one of
the values it reports - a line's glyph count for Vulkan and the GL
drivers, the width and the shared pen for D3D11, which keeps its own -
reads it as void in its macro, so GCC 15 and clang no longer warn that
the layout's counter is set but never used.
The compile matrix builds each driver drawing through the layout with
clang and the warning made an error.
The GL core driver's scRGB/HDR10 state lives outside the slang guard,
and what needs the slang pipelines is inside one: the context's HDR
framebuffer is taken up only with slang, the HDR10-to-SDR downconvert
and the end-of-frame scRGB encode are compiled only with it, and the
ribbon VBO helper only where its caller is. A build without slang - the
C89 lane is one - compiles again, and draws SDR as it always has.
The compile matrix checks gl3.c both with and without slang.
The compile matrix checks gfx/drivers_font_renderer/coretext.c and the
font driver's Apple branch, macOS and iOS, against stand-ins for the
CoreFoundation, CoreGraphics and CoreText declarations they use, so a
change to the rasterizer interface is caught before the Apple jobs.
samples/gfx/font_lifecycle gains a fallback test: two fonts with no
glyph for a set of codepoints, on two threads, ask for the same fallback
face at once, with real stb and real rthreads behind font_driver.c. The
file has to be read once and every glyph has to arrive. It runs in the
ASan/UBSan check and again under TSan in Linux-samples-gfx.yml.
The Visual Studio 2005 to 2017 projects build the network stack as the
2019 and 2022 ones do: the TLS client, the keychain, and the SMB and NFS
clients. What kept them out was the CA bundle, one 255 KB string, where
MSVC before 2019 stops at 65535 bytes (fatal error C1091). net/cacert.h
now holds it in five arrays, each under 60000 bytes and ending where a
certificate does, and x509_trust_load_pem_parts() loads them all into
one trust store with no copy. tools/cacert_split.py writes the header,
from a new cacert.pem or from itself, byte for byte the same bundle.
The rest already kept to what those compilers take: C89, the LL/ULL
suffixes code they build uses, and Windows entry points resolved at run
time. The compile matrix builds the stack for 32-bit Windows in C89 at
the 0x0410 and 0x0501 floors, and checks no part of the bundle reaches
the limit.
The 3DS, Vita and Switch build smb://: the SMB and Kerberos clients
reach the network only through libretro-common's socket helpers, and
the crypto they rest on draws on each console's hardware random number
generator. The Wii U, whose crypto has only a clock to stir, is left
out: SMB derives its signing and sealing keys from that randomness. The
3DS keeps its SMB transfers at 64 KiB, as it does NFS's.
The compile matrix builds the SMB client, the Kerberos client and the
SMB VFS backend for each of the three under their Makefiles' defines.
The 3DS, Vita, Switch and Wii U build nfs:// - the NFS client needs none
of the crypto the RAM-starved consoles leave out, and it reaches the
network only through libretro-common's socket helpers, which these
consoles already build. Where a console's socket layer may not sleep
in a select() with no descriptors, the grace-period wait takes the
platform's own sleep (RARCH_CONSOLE); the 3DS keeps its transfers at
64 KiB, where four connections at the 1 MiB other platforms grow to
would hold 8 MiB of buffers for Wi-Fi that gains nothing from them.
The compile matrix builds the client, its VFS backend and the
prefetcher for each of the four under the defines their Makefiles
set: Wii U against its own wiiu/include, Vita against new stubs of
vitasdk's socket headers.