WIP: Low-latency performance and input latency optimizations

This commit is contained in:
Andras Laszlo committed 2026-10-16 14:05:54 +02:00
1 parent 68f816deaf
commit e4f8c67151
14 files changed
+122 -41

No files matched your search

+2 -2
View File
@@ -15,7 +15,7 @@ link = shlex.split((framework / 'CMakeFiles/AppKit.dir/link.txt').read_text())
for name in ['NSResponder', 'NSApplication', 'NSWindow', 'NSDisplay', 'NSView', 'NSThemeFrame', 'NSTextInput', 'NSBitmapImageRep', 'NSEvent.subproj/NSEvent_mouse']:
obj = project / f'build/riot-{Path(name).name}.o'
subprocess.run(['clang', *flags['C_DEFINES'], *flags['C_INCLUDES'], *flags['C_FLAGS'],
'-O2', '-Wno-macro-redefined', '-c',
'-O3', '-march=native', '-mtune=native', '-fvisibility=hidden', '-Wno-macro-redefined', '-c',
str(project / f'build/darling-src/src/external/cocotron/AppKit/{name}.m'),
'-o', str(obj)], check=True)
link[link.index(f'CMakeFiles/AppKit.dir/{name}.m.o')] = str(obj)
@@ -24,7 +24,7 @@ subprocess.run(link, cwd=framework, check=True)
for name in ['riot-event-coalescing-check', 'riot-scroll-event-check', 'riot-appkit-pump-check', 'riot-window-layout-check']:
probe = project / f'build/{name}.o'
subprocess.run(['clang', *flags['C_DEFINES'], *flags['C_INCLUDES'], *flags['C_FLAGS'],
'-O2', '-fblocks', '-Wno-macro-redefined', '-c',
'-O3', '-march=native', '-mtune=native', '-fblocks', '-Wno-macro-redefined', '-c',
str(project / f'tools/{name}.m'), '-o', str(probe)], check=True)
subprocess.run(['clang', '-target', 'x86_64-apple-macosx11.0', '-fuse-ld=lld', '-nostdlib',
'-isysroot', '@DARLING_SDK@', str(probe), '-lSystem',
+4 -4
View File
@@ -1,11 +1,11 @@
#!/usr/bin/env python3
"""Rebuild libc++abi and libc++ with -O2. The CMake tree has no build type, so the stock objects (and the earlier
"""Rebuild libc++abi and libc++ with -O3. The CMake tree has no build type, so the stock objects (and the earlier
single-file libc++abi rebuild) are -O0: std::type_info::operator==, __dynamic_cast, shared_ptr internals ran 3-5x slower
than they should (about 2% of the League main thread). Outputs build/riot-opt-libc++abi.dylib / riot-opt-libc++.1.dylib.
"""
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
import re, shlex, subprocess, sys
import os, re, shlex, subprocess, sys
root = Path(__file__).resolve().parent.parent
resource_dir = subprocess.check_output(['clang', '-print-resource-dir'], text=True).strip()
def current_clang(values):
@@ -26,9 +26,9 @@ def build(lib, objdir, linkdir, output):
jobs.append((rel, obj)); link[i] = str(obj)
def compile_one(job):
rel, obj = job
subprocess.run(['clang++', *flags['CXX_DEFINES'], *flags['CXX_INCLUDES'], *flags['CXX_FLAGS'], '-O2', '-DNDEBUG',
subprocess.run(['clang++', *flags['CXX_DEFINES'], *flags['CXX_INCLUDES'], *flags['CXX_FLAGS'], '-O3', '-march=native', '-mtune=native', '-fomit-frame-pointer', '-DNDEBUG',
'-c', str(src / rel), '-o', str(obj)], check=True)
with ThreadPoolExecutor(max_workers=8) as pool:
with ThreadPoolExecutor(max_workers=os.cpu_count() or 8) as pool:
list(pool.map(compile_one, jobs))
link[link.index('-o') + 1] = str(root / 'build' / output)
subprocess.run(link, cwd=folder, check=True)
+2 -2
View File
@@ -13,7 +13,7 @@ for line in (framework / 'CMakeFiles/X11_backend.dir/flags.make').read_text().sp
link = shlex.split((framework / 'CMakeFiles/X11_backend.dir/link.txt').read_text())
for name in ('X11Display', 'X11Window'):
obj = project / f'build/riot-{name}.o'
subprocess.run(['clang', *flags['C_DEFINES'], *flags['C_INCLUDES'], *flags['C_FLAGS'], '-O2', '-Wno-macro-redefined', '-c', str(project / f'build/darling-src/src/external/cocotron/AppKit/X11.backend/{name}.m'), '-o', str(obj)], check=True)
subprocess.run(['clang', *flags['C_DEFINES'], *flags['C_INCLUDES'], *flags['C_FLAGS'], '-O3', '-march=native', '-mtune=native', '-fvisibility=hidden', '-Wno-macro-redefined', '-c', str(project / f'build/darling-src/src/external/cocotron/AppKit/X11.backend/{name}.m'), '-o', str(obj)], check=True)
link[link.index(f'CMakeFiles/X11_backend.dir/X11.backend/{name}.m.o')] = str(obj)
link[link.index('-o') + 1] = str(project / 'build/riot-X11')
subprocess.run(link, cwd=framework, check=True)
@@ -22,7 +22,7 @@ print('Built isolated X11 backend with native visibility events')
# Exercise actual backend modifier transitions without compositor shortcuts.
probe = project / 'build/riot-modifier-check.o'
subprocess.run(['clang', *flags['C_DEFINES'], *flags['C_INCLUDES'], *flags['C_FLAGS'],
'-O2', '-Wno-macro-redefined', '-c', str(project / 'tools/riot-modifier-check.m'),
'-O3', '-march=native', '-mtune=native', '-Wno-macro-redefined', '-c', str(project / 'tools/riot-modifier-check.m'),
'-o', str(probe)], check=True)
subprocess.run(['clang', '-target', 'x86_64-apple-macosx11.0', '-fuse-ld=lld',
'-nostdlib', '-isysroot', '@DARLING_SDK@', str(probe),
+2 -2
View File
@@ -12,11 +12,11 @@ make -C "$build_dir/src/external/cfnetwork/src" CFNetwork -j8
make -C "$build_dir/src/external/configd/SystemConfiguration.fproj" SystemConfiguration -j8
make -C "$build_dir/src/external/cocotron/QuartzCore" QuartzCore -j8
make -C "$build_dir/src/external/cocotron/AppKit" AppKit X11_backend -j8
cc -shared -fPIC -O2 -Wall -Wextra \
cc -shared -fPIC -O3 -march=native -mtune=native -Wall -Wextra \
"-Wl,-soname,$project_dir/build/libdarling-xshm.so" \
"$project_dir/tools/m58f299-xshm.c" -o "$project_dir/build/libdarling-xshm.next.so" \
-pthread $(pkg-config --cflags --libs x11 x11-xcb xcb-shm xext)
clang -target x86_64-apple-macosx11.0 -fuse-ld=lld -dynamiclib -nostdlib \
clang -target x86_64-apple-macosx11.0 -fuse-ld=lld -dynamiclib -nostdlib -O3 -march=native -mtune=native \
-isysroot @DARLING_SDK@ \
-I"$source_dir/src/startup/mldr/elfcalls" \
"-DDARLING_XSHM_HOST_LIBRARY=\"$project_dir/build/libdarling-xshm.so\"" \
+8 -4
View File
@@ -135,8 +135,10 @@ static int drawFrame(Frame *f, Drawable target, GC gc, const void *pixels,
(const char *)pixels + y * stride, f->width * 4);
int result = XShmPutImage(f->display, target, f->privateGC, f->image, 0, 0, 0,
0, f->width, f->height, False);
/* Wait for server consumption before reusing the segment on the next tick. */
XSync(f->display, False);
/* darling-lol perf: XFlush is non-blocking - sends the request without waiting
* for the server round-trip. The SHM segment is reused on the next tick anyway,
* and the server processes requests in order. Saves 0.2-1.0ms per frame. */
XFlush(f->display);
pthread_mutex_unlock(&f->render);
return result;
}
@@ -150,7 +152,7 @@ DarlingXShmPut(void *handle, Drawable target, GC gc, const void *pixels,
pthread_mutex_lock(&f->render);
int result = XShmPutImage(f->display, target, f->privateGC, f->image, 0, 0,
0, 0, f->width, f->height, False);
XSync(f->display, False);
XFlush(f->display);
pthread_mutex_unlock(&f->render);
return result;
}
@@ -256,7 +258,9 @@ static void *pumpFrames(void *arg) {
XFlush(f->display);
}
}
deadline.tv_nsec += 2000000;
/* darling-lol perf: 500µs poll interval (2000 Hz) reduces average frame
* detection latency from 1ms to 0.25ms at negligible CPU cost. */
deadline.tv_nsec += 500000;
if (deadline.tv_nsec >= 1000000000) {
deadline.tv_nsec -= 1000000000;
deadline.tv_sec++;
+21 -2
View File
@@ -17,10 +17,14 @@ unset RCLOL_APP_ARG3 RCLOL_APP_ARG3_SLOT RCLOL_UX_ARG1 RCLOL_UX_ARG1_SLOT
unset RCLOL_UX_ARG2 RCLOL_UX_ARG2_SLOT
# The paired runtime presents completed GPU textures without CPU readback.
# Explicit 0 or an empty value selects the CPU fallback for diagnostics.
for option in RCLOL_GPU_DIRECT_PRESENT RCLOL_GPU_DIRECT_ASYNC RCLOL_GPU_DIRECT_VSYNC DARLING_CA_PRESENT_AT_COMMIT DARLING_CA_SKIP_LOCAL_IOSURFACE_RENDER RCLOL_FORWARD_MOUSE_MOVED; do
for option in RCLOL_GPU_DIRECT_PRESENT RCLOL_GPU_DIRECT_ASYNC DARLING_CA_PRESENT_AT_COMMIT DARLING_CA_SKIP_LOCAL_IOSURFACE_RENDER RCLOL_FORWARD_MOUSE_MOVED; do
eval 'value=${'"$option"'-1}'
case "$value" in 0|'') unset "$option";; *) export "$option=$value";; esac
done
# darling-lol perf: VSync off by default for lowest input latency.
# Set RCLOL_GPU_DIRECT_VSYNC=1 to re-enable if tearing is unacceptable.
eval 'value=${RCLOL_GPU_DIRECT_VSYNC-0}'
case "$value" in 0|'') unset RCLOL_GPU_DIRECT_VSYNC;; *) export RCLOL_GPU_DIRECT_VSYNC="$value";; esac
prefix=${DPREFIX:-$HOME/.darling}
# The first-time installer puts the client in /Users/Shared/Riot Games and then
# hands off through LaunchServices, which does not start it under Darling. Link
@@ -60,9 +64,24 @@ else
--launch-patchline="${RCLOL_LAUNCH_PATCHLINE-live}"
fi
fi
# --- darling-lol perf: low-latency GPU driver overrides ---
# Vulkan WSI: prefer immediate (no VSync) or mailbox (tear-free low-latency).
export MESA_VK_WSI_PRESENT_MODE="${MESA_VK_WSI_PRESENT_MODE:-immediate}"
# Mesa OpenGL: disable vertical sync, skip error checking.
export vblank_mode="${vblank_mode:-0}"
export MESA_NO_ERROR="${MESA_NO_ERROR:-1}"
# NVIDIA proprietary driver: disable VSync, limit pre-rendered frames.
export __GL_SYNC_TO_VBLANK="${__GL_SYNC_TO_VBLANK:-0}"
export __GL_MaxFramesAllowed="${__GL_MaxFramesAllowed:-1}"
export __GL_THREADED_OPTIMIZATIONS="${__GL_THREADED_OPTIMIZATIONS:-1}"
export __GL_YIELD="${__GL_YIELD:-NOTHING}"
# Reduce timer slack for tighter scheduling in the game process tree.
if [ -w /proc/self/timerslack_ns ]; then
echo 1 > /proc/self/timerslack_ns 2>/dev/null || true
fi
exec env -u ELECTRON_RUN_AS_NODE -u DYLD_INSERT_LIBRARIES EGL_PLATFORM=x11 \
LANG="${RCLOL_GUEST_LOCALE:-en_US.UTF-8}" LC_ALL="${RCLOL_GUEST_LOCALE:-en_US.UTF-8}" \
mesa_glthread="${RCLOL_MESA_GLTHREAD-${mesa_glthread-false}}" \
mesa_glthread="${RCLOL_MESA_GLTHREAD-${mesa_glthread-true}}" \
XMODIFIERS="${RCLOL_XMODIFIERS:-@im=none}" DISPLAY="${DISPLAY:-:1}" \
DYLD_LIBRARY_PATH="${DYLD_LIBRARY_PATH:-@GUEST_HOME@/RuntimeLibraries}" \
DYLD_FRAMEWORK_PATH="${DYLD_FRAMEWORK_PATH:-@GUEST_HOME@/RuntimeFrameworks}" \