27 Commits
Author SHA1 Message Date
LibretroAdmin ec82925c60 No allocations after boot: VI config read on change, workers' compile memory at start
VideoInterface read four settings with Config::Get per field and per SI
poll; the first field after boot found the cache stale and parsed the
value through an istream, allocating. They are read where config
changes, as the VI overclock factor already was.

A compile worker given nothing during boot made its first shader text
block in play. Each worker now makes its rslc arena and three text
blocks as it starts, at boot.

Both play allocation baselines are 0.
2026-11-09 20:37:28 +01:00
LibretroAdmin fa3c5e69bf Vulkan: logic op set per draw, ubershader logic ops precompiled
Where the device sets the logic op per draw, its mode is no longer part
of a pipeline, so one ubershader pipeline with integer output draws
every mode. The precompile also builds the logic op pipelines with
dual-source output asked for, as BlendingState::Generate leaves it.
The stats build counts the pipelines the driver compiles or links, and
those a draw waits for.
2026-11-08 17:28:30 +01:00
LibretroAdmin b08783a161 Stutter harness: stats build, corpus, gate and Vulkan baseline
make STATS=1 builds parallel_gx1_libretro_stats with counters for each
kind of draw-path compile, wait and cache write, worker compiles, and
every shader and pipeline made; release builds have none. Tools/stutter
generates a synthetic FIFO corpus, runs it in the four cache states,
times parent and candidate ABBA, compares pictures, and gates the
counters against baseline.txt and the parent.
2026-11-08 17:01:39 +01:00
LibretroAdmin a108f60c5e VideoCommon: shader compiles queue pooled items without allocating
The shader cache keeps its compile items in chunks and reuses them, so a
shader or pipeline compiled while the game runs allocates nothing. Each
item embeds the compiler's link and callbacks, so a finished one is pushed
back as it is, and a pipeline waiting on its stages queues itself again.
The compiler keeps the waiting items in a heap by priority and order, and
is a member of the shader cache rather than an object of its own.
2026-11-07 22:59:17 +01:00
LibretroAdmin bc09a84dd1 GL: programs compiled on the driver's threads, drawn with once linked
Where the driver compiles on threads of its own
(GL_KHR_parallel_shader_compile or the ARB one), the asynchronous
shader modes on OpenGL compile in the background on the frontend's
context alone: a missing program's compile and link are started, a
couple of work items a frame, and its draws use the ubershaders, or
are skipped, until GL_COMPLETION_STATUS says the link is done; its
link is checked, its variables set and its binary written to the cache
then. A program drawn with before it is done is waited for there. A
software rasterizer, which compiles when it first draws, compiles on
the spot as before.

The shader compiler gets a deferred mode for it, without threads,
compiling the items waiting a few at a time, and AbstractPipeline tells
whether a pipeline's compile is still running and whether it can be
drawn with. With the driver's threads alone, every ubershader pipeline
there can be is not built in the background.
2026-11-07 02:05:36 +01:00
LibretroAdmin 2dd80c5c2e VideoCommon: shader compiler workers below the emulation threads
The shader compiler's worker threads run at a lower priority than the
threads that emulate, on Windows (below normal) and Linux (nice 5): on
a machine with fewer cores than busy threads, what compiles in the
background waits, not the frame being emulated. Common gets
LowerCurrentThreadPriority for it.
2026-11-06 23:45:19 +01:00
LibretroAdmin 1e2dbf6616 Remove all sleeping and wall-clock pacing from the core
retro_run runs one video frame and the frontend paces it, so the core no
longer paces itself:

- The speed limiter is gone: CoreTiming::Throttle and its host-time
  targets, VI skip, the presenter's presentation-time wait,
  PrecisionTimer, PerformanceMetrics/PerformanceTracker, and the
  emulation speed, precision timing, rush/smooth presentation and VI
  skip settings and core options. The Dolphin IOS device reports 100%
  and ignores speed limits a guest asks for.
- Common/FrameClock.c (C89) counts retro_run calls. Background threads
  that acted every so many milliseconds wait for a number of frames
  instead: real-Wiimote pool upkeep, scanning, write tests and
  reconnect retries, USB scanning, the USB Gecko and GBA link
  listeners, the BBA read thread, memory card flushing and the WC24
  scheduler. Shutdown wakes every waiter.
- Waits that polled or timed out now block until signalled: dual-core
  boot, PauseAndLock in the GPU loop, CPU thread jobs, shader
  compilation progress, BlockingLoop and ParallelFor setup and
  teardown.
- Bluetooth passthrough submits transfers straight to libusb; the
  output worker and its timed sleep are deleted, HCI command timeouts
  count emulated time, and blocking firmware commands wait for the
  adapter's events.
- Real Wiimote reports go out when produced; delayed ones carry a
  frame number.
- Common::Flag sits on retro_atomic.
- Deleted: SleepCurrentThread, YieldCPU, Common::SleepUntil,
  Event::WaitFor, BlockingLoop::WaitYield, timer resolution changes,
  the play-time tracker, Host_YieldToUI, FrameTiming::ThrottleFrame
  leftovers and the never-used DO_WAIT_FOR_WIIMOTES mode.
2026-11-05 22:05:03 +01:00
LibretroAdmin cb214d1034 Core, VideoCommon: drop std::this_thread waits
Waits that polled now block on an eventcount that the waited-on thread
notifies:

- Booting in dual core waits for the CPU thread to reach its run loop
  instead of polling every millisecond.
- AsyncShaderCompiler::WaitUntilCompletion wakes as each worker
  finishes an item instead of every 33 ms.

Timed sleeps go through Common::SleepUntil and SleepCurrentThreadUs,
built on retro_sleep_us: the CoreTiming throttle, PrecisionTimer, real
Wiimote report pacing, Bluetooth timed transfers, the Linux L2CAP
connect retry and the BBA read thread's idle wait.

FrameTiming::ThrottleFrame had no callers and is deleted.
2026-11-05 20:11:34 +01:00
LibretroAdmin 407a632adc Core, VideoCommon: replace the per-frame locks with atomics
CPU: the state machine drops its two mutexes and two condition
variables.  The state is one atomic word, which the JIT still reads in
place; PowerDown sticks through a CAS.  The CPU thread marks itself
active and then rechecks for a pause or a state change, and a pausing
thread stores its request and then waits for the flag to drop, a
Dekker pair, so neither misses the other.  Waits park on eventcounts.
A step request and its Event travel as one exchanged pointer, pending
jobs are an MPSC stack run in order, and SetStepping and PauseAndLock
still run one at a time, through a claimed flag.

Core: the recursive core mutex goes.  Stop moves the state with a CAS,
and PauseAndLock pairs are already serialized by the CPU's claim.  Host
jobs are an MPSC stack the host thread moves, in order, into its own
queue, which keeps HostDispatchJobs re-entrant.  RunOnCPUThread waits
on a Common::Event instead of a binary semaphore, and OneShotEvent is
removed.

State: the transferable shared mutex that counted save tasks is a
counter and an eventcount; the slot readers and the flush hook wait for
it to reach zero.  TransferableSharedMutex is removed.  WaitableFlag
parks on an eventcount.

PixelEngine: the token, its interrupt flags and the raised-event flag
are one atomic word; the video thread merges into it and schedules the
event only on the edge, the CPU thread takes the flags with a CAS.
Savestates keep the old fields.

VertexLoaderManager: the loader map is a fixed set of buckets, each a
list pushed with a CAS and read without a lock by the main and the
preprocessing thread; two threads making the same loader keep one.

AsyncShaderCompiler: the pending queue is the video thread's own.  It
hands the most urgent items to two slots per worker, and finished items
come back on an MPSC stack, so neither side takes a lock.

OSD messages are posted to an MPSC stack and taken in by the video
thread when it draws; a screenshot request is one exchanged string.

Also removed, being unreachable: the surface change and resize requests
nothing sends (and the swap mutex guarding them), the ImGui keyboard
and mouse input nothing feeds (and the ImGui mutex, as only the video
thread touches the context now), ClearMessages, and the libretro Vulkan
WaitForPresentation with its mutex and condition variable.
2026-11-05 20:11:27 +01:00
LibretroAdmin 767c898df8 Move every thread onto rthreads and add a lock-free parallel_for
No std::thread, std::async, std::future or std::promise is left. Each
thread is an sthread with a plain entry point: Common::ThreadEntry<&C::F>
turns a member function into one, Common::JoinThread joins and clears a
handle, and Common::StartDetachedThread covers the fire-and-forget users.

Common/ParallelFor.{h,c} (C89) runs fn(ctx, i) for i in [0, count) on a
persistent pool of one worker per extra core plus the caller. Jobs are
claimed with an atomic counter, workers park on an eventcount between
batches, and the batch hand-off is a seq_cst users/active pair, so there
is no lock anywhere. A caller that finds the pool busy runs its batch
serially instead of waiting. retro_deinit joins the pool.

- VolumeWii::HashGroup spawned 64 threads per 2 MiB group and
  EncryptGroup another one per core; both are now parallel_for batches
  on the pool. The H1/H2 tail is a few small hashes and runs inline.
- VolumeVerifier spawned up to five std::async threads per chunk; the
  chunk's tasks now go to one persistent worker that fans them out with
  parallel_for, still overlapping the next read. The Redump lookup is an
  sthread joined in Finish or the destructor.
- The dual-core "GPU thread" in Core only set a thread_local on itself
  and exited, since the frontend runs the GPU loop. It is gone, along
  with the non-libretro branches of Core.cpp.
- The emu thread is started through Core::StartEmuThread.
- CPU core counts come from cpu_features_get_core_amount().
2026-11-05 13:00:34 +01:00
iwubcode 506e378289 VideoCommon: remove template parameter from lock guards in AsyncShaderCompiler, let type deduction do its thing and improve readability 2025-11-21 01:18:35 -06:00
iwubcode 75c66e35c6 VideoCommon: add method to async shader compiler to clear pending/completed work (used on shutdown), this will in turn clear up any resources that the worker items may have held onto 2025-11-21 01:17:45 -06:00
Javier Martinez 7dec083af5 Refactor: Make loop non-infinite instead in AsyncShaderCompiler. 2025-02-05 20:06:59 -05:00
mitaclaw eb92d6f0a8 Core::GetState: Avoid Global System Accessor 2024-04-08 16:23:23 -07:00
Silent dcad3ec892 Allow to interrupt shader precompilation by stopping emulation 2022-06-10 17:11:32 +02:00
Pokechu22 2025763420 Treewide: Adjust order of includes 2021-12-10 14:49:57 -08:00
Pierre Bourdon e149ad4f0a treewide: convert GPLv2+ license info to SPDX tags
SPDX standardizes how source code conveys its copyright and licensing
information. See https://spdx.github.io/spdx-spec/1-rationale/ . SPDX
tags are adopted in many large projects, including things like the Linux
kernel.
2021-07-05 04:35:56 +02:00
Lioncash 3d9b2aa005 VideoCommon: Migrate over to fmt
Migrates off the printf-based formatting where applicable.
2020-11-17 21:23:58 -05:00
Shawn Hoffman 6ef9d70701 name some threads 2020-08-22 17:22:07 -07:00
Stenzek 78588ce79d ShaderCache: Use imgui for shader compilation dialog 2019-01-25 11:15:57 +10:00
Markus Wick 98b4716902 Merge pull request #6442 from stenzek/async-compiler-priority
ShaderCache: Implement compile priority
2018-03-19 09:16:53 +01:00
Stenzek 93865b327f ShaderCache: Implement compile priority
Currently, when immediately compile shaders is not enabled, the
ubershaders will be placed before any specialized shaders in the compile
queue in hybrid ubershaders mode. This means that Dolphin could
potentially use the ubershaders for a longer time than it would have if
we blocked startup until all shaders were compiled, leading to a drop in
performance.
2018-03-17 01:53:11 +10:00
Lioncash 50a476c371 Assert: Uppercase assertion macros
Macros should be all upper-cased. This is also kind of a wart that's
been sticking out for quite a while now (we avoid prefixing
underscores).
2018-03-14 22:03:12 -04:00
Stenzek 517a977444 ShaderCache: Fix several issues in background shader compiling
- In D3D, shaders could be compiled on the main thread, blocking
startup.
- Reduced the latency between a pipeline being requested and used in all
backends in hybrid ubershader mode, when no shader stages were present.
- Fixed a case where async compilation could cause the same UID to be
appended multiple times to the UID cache.
- Fix incorrect number of threads being used when immediately compile
shaders was enabled.
2018-03-15 01:50:47 +10:00
Stenzek e31cc1f679 ShaderCache: Implement background shader compilation
This enables shaders to be compiled while the game is starting, instead
of blocking startup. If a shader is needed before it is compiled,
emulation will block.
2018-03-10 16:11:19 +10:00
Stenzek c8f31656cb VideoBackends: Support a different number of threads for precompiling
At runtime, we only really want a single shader compiler thread.
However, for initial boots, we can use a higher number to speed things
up.
2017-07-30 17:43:59 +10:00
Stenzek 0a9574eaa1 VideoCommon: Add AsyncShaderCompiler class implementation 2017-07-30 17:43:59 +10:00