Port the fullscreen policy omitted when adapting PR #12. Track requested fullscreen state across frame and style changes, exclude unmanaged windows, and use EWMH REMOVE when leaving fullscreen.
Extend the native geometry probe and document passive tracing for the reported vertical click offset, whose cause remains unconfirmed.
CGDisplayScreenSize returned 0x0 for any display with EDID (upstream left
that branch unimplemented). League divides by it for its camera aspect
ratio, so the view-projection x row became NaN: every 3D vertex was
discarded, the scene showed only its blue clear colour, and world clicks
were ignored. Read the size from the EDID detailed timing (mm) or basic
parameters (cm), fall back to 96 dpi, and use the main display for an
unknown id.
CGDisplayCopyAllDisplayModes returned NULL for display 0 (a window off
every screen), which League passes straight to CFArrayGetCount. Fall back
to the main display, then to an empty array.
Add riot-display-modes-check covering both for the main display,
display 0 and an unknown id.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Adapt the geometry fix from PR #12 to the current relative-mouse implementation. Keep display IDs independent of primary-first screen ordering, translate window and pointer coordinates consistently, and invalidate geometry on both RandR event types.
Handle failed RandR snapshots and free EDID data. Add isolated native geometry regression coverage and use the configured SDK when linking the X11 probe.
Validated all 30 component patches, the X11 and CoreGraphics builds, six native geometry groups, and the existing relative-mouse checks. The user confirmed the installed fix works on 2026-10-16.
Co-authored-by: Maka <[email protected]>
CGAssociateMouseAndMouseCursorPosition(false) used to warp the pointer to the
window center, freeze the reported position there and treat the game's own
CGWarpMouseCursorPosition calls as motion. On Xwayland, which ignores warps
while the cursor is visible, this left League's cursor stuck in the middle.
The backend now keeps a frozen virtual cursor: physical motion only produces
deltas (deltaY positive downwards), application warps move the virtual cursor
and their echoes are dropped, mouseLocation returns it, and the pointer is only
warped back where the server honours warps. The grab no longer uses the
invalid FocusChangeMask and is released and retaken across focus changes.
setCursor: no longer re-sends XDefineCursor/XFlush when the window already has
that cursor; League set it about 190 times per second.
Also carries the opt-in input trace (/tmp/rclol-input-trace in the guest).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Traverse the layer tree before compositing so nested Metal layers consume queued drawables and recycle their pool. Add a nested presentation probe covering pool reuse and Vulkan-to-OpenGL pixel readback.
NVIDIA's GL rejects GL_LINEAR_TILING_EXT with GL_INVALID_VALUE, so the
linear internal image could not be imported and the window stayed black.
Pick the tiling by GL_VENDOR; other drivers keep linear.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
NSApplication's attention timer calls -[CGWindow flashWindow], which X11Window
did not override; the base class raised an uncaught abstract-invocation
exception and LeagueClientUx aborted (and restarted every ~50s). Mark the
window as demanding attention through _NET_WM_STATE instead.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Wait up to 2 s for the cancellation callback instead of one 50 ms run-loop
pass, count only callbacks without stored addresses so a completed lookup
cannot pass as a cancellation, print the failing stage, and have the runner
require the exact success line since Darling can exit zero after a trap.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
League sets framebufferOnly=NO on its CAMetalLayer, and QuartzCore read
that as needing host-visible coherent memory, so the game's final
render target and the linear image handed to OpenGL both lived in
system RAM (type 2 on the RX 6600) and crossed PCIe every frame.
framebufferOnly=NO only lets Metal sample or blit the texture: nothing
maps either image (replaceRegion aborts, getBytes is a stub, Indium
maps only Shared/Managed buffers).
Drawables now take the first allowed DEVICE_LOCAL type whatever
framebufferOnly says; the guest file /tmp/metal-no-drawable-vram
restores the old placement. metal-device.log shows drawable-vram=on and
storage=vram.
A native EGL/RADV test exported the drawable's linear image from VRAM
and imported it into GL with no errors and identical pixels. In a
practice-tool baron fight on the RX 6600 with the same champion it ran
about 20 FPS faster and the same when idle; not yet measured in an ARAM.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
find_package(LLVM CONFIG) also searches <prefix>/llvm/lib/cmake/llvm for
every PATH entry, before the system prefixes. With /opt/rocm/bin on PATH
it found ROCm's LLVM 22.0.0git, whose llvm-config reports no shared
library, and 4e88b79's fallback to the llvm-config on PATH then rejected
the system LLVM 23 because its major differs from the ROCm headers, so a
fresh configure failed (issue #1).
Before find_package, keep LLVM_DIR only if the llvm-config next to it
reports a shared library; otherwise, or when LLVM_DIR is unset, use the
llvm-config on PATH that does and take its --cmakedir. A working pinned
LLVM_DIR is left alone.
Checked with a fake ROCm prefix on PATH: plain find_package picks it;
the new code picks /usr/lib/cmake/llvm (LLVM 23) on a fresh configure,
replaces a cached ROCm LLVM_DIR, and keeps a working cached
/usr/lib64/cmake/llvm. A standalone configure of Indium with the fake
ROCm on PATH completes with the system LLVM.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Indium and QuartzCore took the first memory type a resource allowed. The
Vulkan spec orders a type with no flags before every DEVICE_LOCAL type,
and NVIDIA exposes such system-RAM types, so on NVIDIA private buffers,
textures and framebufferOnly drawables could land in system RAM. They
now take the first allowed DEVICE_LOCAL type and fall back to the old
choice; shared and managed resources are unchanged.
The drawable's exported image is a dedicated Vulkan allocation, but the
OpenGL import never set GL_DEDICATED_MEMORY_OBJECT_EXT, which
EXT_external_objects requires. Mesa ignores it; it is the suspected
cause of the black screen on NVIDIA in issue #3. The import's GL errors
were never checked (reportGLErrors is compiled out), so a failure was
silent.
/tmp/metal-device.log now lists the selected device's memory heaps and
types, the memory type chosen per resource kind (with the old choice and
changed=yes/no), and the result of the first drawable and semaphore
imports into OpenGL (later ones only on failure).
Practice match on the RX 6600: all choices changed=no, import
dedicated=yes with no GL errors, semaphore ok, match=yes. Not run on
NVIDIA.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A leftover LLVM_DIR can point at a removed LLVM whose llvm-config exists
but whose library is gone, which made configure fail on LLVM 23 hosts.
Try the tools-dir llvm-config, then the one on PATH, and accept only one
that matches the header major and reports a shared library.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
On a hybrid laptop (issue #3) Indium took whichever Vulkan device the
loader listed first, usually the integrated GPU, and still created a
VkDevice on every other supported GPU, waking a discrete GPU it never
used. Drawables reach the presenting OpenGL context as opaque FDs, which
only work on one physical device, and nothing checked that.
Indium now appends the device list, the selected device and the reason
to guest /tmp/metal-device.log, and creates a VkDevice for the selected
device only (/tmp/metal-all-devices restores the old behaviour).
/tmp/metal-gpu or METAL_INDIUM_GPU selects a device by index or name
for diagnosis. QuartzCore logs the presenting GL renderer and compares
its device UUID with the Vulkan device's (match=yes / MISMATCH); it
queries Vulkan itself, so it needs no new libindium export.
On the RX 6600 desktop the game selected RADV, created 1 VkDevice of 2
supported (lavapipe no longer gets one) and logged match=yes in a match.
Running on NVIDIA through prime-run is documented but not validated.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
After a pull that changed a patch, prepare.py stopped: the patch neither
applied nor reverse-applied to a tree holding its earlier version. Now
it looks for the earlier version applied in that component -- the copy
it records in build/applied-patches, or a version from this
repository's history -- reverts exactly it and applies the new one.
It never resets a repository; when nothing matches it stops and names
the repository with other edits, and it restores the earlier version
if the new one does not apply.
scripts/update.sh runs build.sh, the base install and
install-runtime.sh, and refuses to start while a Riot Client or League
process is open, since the install steps stop Darling.
Checked on a sandbox Indium checkout holding the previous patch: the
result matches a clean apply, a second run is a no-op, an unrelated
local edit survives and a conflicting one stops with the error.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
LLVM 23 represents vector splats such as `<3 x float> zeroinitializer`
as vector-typed ConstantFP/ConstantInt values instead of
ConstantAggregateZero/ConstantDataVector. Iridium only handled scalar
ConstantFP/ConstantInt, so on hosts with LLVM 23 nearly every League
shader failed to translate: the r3dlog fills with "Failed to compile
shader", the loading screen hits "Material Missing Pipeline" and the
game crashes. Our matches had only run the overlay pinned to LLVM 22.
Declare the scalar element and splat it into a constant composite.
Offline, on the 74,112 metallibs in ShaderCache.metal.wad.client,
LLVM 23 went from ~2% to 74,108 translated, the same set as LLVM 22
(the 4 remaining failures are pre-existing on both); a sample of the
LLVM 23 SPIR-V passes spirv-val for Vulkan 1.3. Confirmed in a match
with the Iridium overlay built against the system LLVM 23.
RIOT_IRIDIUM_SYSTEM_LLVM=1 makes build-riot-indium-runtime.py ignore
the LLVM 22 pin, to build what a fresh checkout gets.
Refs #1
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Darling's libvDSP was almost entirely void stubs. Chromium's Blink
WebAudio on macOS uses vDSP_vsmul for any GainNode gain other than 0 or
1, so with the League client's master volume below 100% the master gain
output buffer was never written: silence when starting below 100%, and
the last block repeating as a buzz when lowering the volume. vDSP_vadd
was also a stub, so simultaneous sounds were not summed and a new sound
replaced the previous one.
Implement every vDSP function the Chromium Embedded Framework imports:
vadd, vsub, vmul, vsmul, vsadd, vsma, svesq, vclip, conv, ctoz, ztoc,
zvmul, deq22, deq22D, create_fftsetup, destroy_fftsetup and fft_zrip,
with Apple's argument order and scaling (forward real FFT is 2x the
DFT, inverse unscaled). The FFT is in place and keeps only read-only
twiddles in the setup, which callers share across threads. Build vDSP
at -O2 because it runs on the realtime render thread, and drop the
uncompiled basic.c.
The runtime installer now builds libvDSP and installs it at its
absolute path in the stopped prefix, keeping a .before-vdsp backup.
Verified against naive references for sizes up to 2^15 on the host;
confirmed manually that client sound is fixed at any volume.
Fixes#4
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Fix X11 presentation handoff after resizing, preserve NSView size callbacks, and correct content and backing-layer geometry. Add CoreText font enumeration for the language dropdown and rebuild/install the matching runtime overlays.
Correct CarbonCore Gestalt version queries and roll back proc_listpids for Vanguard testing. Document that VAN -101 can still recur. Include accumulated CoreAudio stream and AudioUnit corrections.
Add standalone font, version, resize and publisher-handoff regressions. Record manual confirmation of the language dropdown and window resizing; all 29 pinned patches and the source/script audit validate.
proc_info callnum 1 (proc_listpids) previously fell through to the unsupported-callnum path and returned ENOTSUP, so process enumeration (e.g. the Riot client's Vanguard kext probe) logged 'sys_proc_info(): Unsupported callnum: 1'.
Walk /proc like _sysctl_proc and _proc_pidinfo_listthreads already do and mirror XNU's filter semantics for PROC_ALL_PIDS, PROC_PGRP_ONLY, PROC_PPID_ONLY, PROC_TTY_ONLY, PROC_UID_ONLY and PROC_RUID_ONLY, with XNU's size-query, ENOMEM and truncation contracts.