Address code review feedback on input handling, pacing, and runtime cleanup

This commit is contained in:
Andras Laszlo committed 2026-10-16 17:50:22 +02:00
1 parent d981cbe8c3
commit 0e2a2dde61
8 files changed
+68 -64

No files matched your search

+8 -8
View File
@@ -2307,7 +2307,7 @@ index 18189404..c683f96a 100644
+- (NSRect) frameForRootRect: (NSRect) rect;
@end
diff --git a/AppKit/X11.backend/X11Display.m b/AppKit/X11.backend/X11Display.m
index 5ae29bf4..516decf3 100644
index 5ae29bf4..d7fb09fc 100644
--- a/AppKit/X11.backend/X11Display.m
+++ b/AppKit/X11.backend/X11Display.m
@@ -48,12 +48,271 @@
@@ -3125,7 +3125,7 @@ index 5ae29bf4..516decf3 100644
+ int xfd = ConnectionNumber(_display);
+ struct pollfd pfd = { .fd = xfd, .events = POLLIN };
+ int timeout_ms = (int)(slice * 1000.0);
+ if (timeout_ms < 1) timeout_ms = 1;
+ if (timeout_ms < 0) timeout_ms = 0;
+ extern long __lolsys_syscall(long, long, long, long, long, long, int);
+ __lolsys_syscall((long)&pfd, 1, timeout_ms, 0, 0, 0, 7 /* Linux poll */);
+ }
@@ -3391,7 +3391,7 @@ index 5ae29bf4..516decf3 100644
[self postEvent: event atStart: NO];
break;
@@ -1160,49 +1855,113 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1160,49 +1855,111 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
// ev->xmotion.x, ev->xmotion.y, ev->xmotion.x_root,
// ev->xmotion.y_root);
@@ -3418,8 +3418,6 @@ index 5ae29bf4..516decf3 100644
+ ev->xmotion.x = clampedX;
+ ev->xmotion.y = clampedY;
+ }
+ } else if (!_relativeMouse.active && window != nil && !_confinedWindow) {
+ [self updateMouseConfinementForWindow: window];
+ }
+
CGPoint lastMotionPos = [window mouseLocationOutsideOfEventStream];
@@ -3531,7 +3529,7 @@ index 5ae29bf4..516decf3 100644
mouseEventWithType: type
location: pos
modifierFlags:
@@ -1211,28 +1970,58 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1211,28 +1968,58 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
clickCount: 1
deltaX: deltaX
deltaY: deltaY];
@@ -3592,7 +3590,7 @@ index 5ae29bf4..516decf3 100644
NSLog(@"FocusIn");
if ([delegate attachedSheet]) {
[[delegate attachedSheet] makeKeyAndOrderFront: delegate];
@@ -1243,28 +2032,59 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1243,28 +2030,61 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
checkForAppDeactivation: NO];
lastFocusedWindow = nil;
}
@@ -3620,7 +3618,7 @@ index 5ae29bf4..516decf3 100644
+ rclolFocusDetailName(ev->xfocus.detail), _relativeRequested, _relativeMouse.active,
+ (unsigned long) _confinedWindow,
+ [NSApp isActive]);
+ if (ev->xfocus.detail == NotifyPointer || ev->xfocus.mode == NotifyGrab || ev->xfocus.mode == NotifyUngrab) {
+ if (ev->xfocus.detail == NotifyPointer || ev->xfocus.detail == NotifyInferior || ev->xfocus.mode == NotifyGrab || ev->xfocus.mode == NotifyUngrab) {
+ /* Pointer boundary crossing or grab transition in XWayland: do NOT release confinement or deactivate window */
+ break;
+ }
@@ -3637,6 +3635,8 @@ index 5ae29bf4..516decf3 100644
+ if (_confinedWindow) {
+ XUngrabPointer(_display, CurrentTime);
+ _confinedWindow = None;
+ _confinedWidth = 0;
+ _confinedHeight = 0;
+ }
+ _otherButtonsDown = 0;
if (window != nil)
+3 -2
View File
@@ -6949,7 +6949,7 @@ index ffd7fe054..a74ffc63f 100644
+ uint64_t current=(uint64_t)now.tv_sec*1000000000ull+now.tv_nsec;
+ uint64_t deadline=ctx->native_next_present_ns;
+ static uint64_t paceNS = 0;
+ if (!paceNS) { const char *hz = getenv("RCLOL_REFRESH_HZ"); int r = hz ? atoi(hz) : 0; paceNS = r > 0 ? 1000000000ull / (uint64_t)r : 1000000ull; }
+ if (!paceNS) { const char *hz = getenv("RCLOL_REFRESH_HZ"); int r = hz ? atoi(hz) : 0; paceNS = (r > 0 && r <= 1000) ? 1000000000ull / (uint64_t)r : 1000000ull; if (paceNS < 1000000ull) paceNS = 1000000ull; }
+ if(!deadline || (current>deadline && current-deadline>paceNS))deadline=current;
+ if(deadline>current){
+ struct timespec wake={deadline/1000000000ull,deadline%1000000000ull};
@@ -8534,7 +8534,8 @@ new file mode 100644
+ if (!refreshNS) {
+ const char *hz = getenv("RCLOL_REFRESH_HZ");
+ int rate = hz ? atoi(hz) : 0;
+ refreshNS = rate > 0 ? 1000000000ull / (uint64_t)rate : 1000000ull;
+ refreshNS = (rate > 0 && rate <= 1000) ? 1000000000ull / (uint64_t)rate : 1000000ull;
+ if (refreshNS < 1000000ull) refreshNS = 1000000ull;
+ }
+ deadline += refreshNS;
+ uint64_t now=nativeMonotonicNS();
+1 -5
View File
@@ -7450,11 +7450,7 @@ new file mode 100644
+ static constexpr VkDeviceSize BlockSize = 32ull << 20;
+ static constexpr VkDeviceSize MaxPooledSize = 4ull << 20;
+ static constexpr VkDeviceSize Granule = 256;
+ // a freed range is not handed out again before this long: work already submitted to the GPU may still read it
+ /* darling-lol perf: the old 1000ms quarantine caused pool exhaustion
+ * and fallback OS allocations during high-churn gameplay. 50ms (~3
+ * frames at 60Hz) is sufficient for in-flight GPU work to drain. */
+ static constexpr std::chrono::milliseconds Quarantine {50};
+ static constexpr std::chrono::milliseconds Quarantine {1000};
+
+ struct Block {
+ VkDeviceMemory memory = VK_NULL_HANDLE;
+7 -4
View File
@@ -5893,11 +5893,14 @@ index b998456..2783a4a 100644
+ __linux_sched_yield_site("SWTCH");
return 0;
}
@@ -696,6 +1613,48 @@ kern_return_t syscall_thread_switch_impl(
.tv_sec = 0,
@@ -693,11 +1610,53 @@ kern_return_t syscall_thread_switch_impl(
mach_msg_timeout_t option_time)
{
struct timespec tv = {
- .tv_sec = 0,
- .tv_nsec = 1000000
+ .tv_nsec = option_time > 0 ? (long)option_time * 1000 : 1000000
+ .tv_sec = option_time > 0 ? (time_t)(option_time / 1000000) : 0,
+ .tv_nsec = option_time > 0 ? (long)((option_time % 1000000) * 1000) : 1000000
};
+
+ /* darling-lol: opt-in trace (host file /tmp/rclol-select-trace) of who calls thread_switch and with which option:
-1
View File
@@ -14,7 +14,6 @@ export RIOT_LAUNCHER_HOST RCLOL_REGION
# client fails under Darling, so start the installed client here.
sh scripts/run.sh || true
unset RIOT_LAUNCHER_HOST
python3 build/runtime/tools/riot-desktop-entry.py || true
prefix=${DPREFIX:-$HOME/.darling}
if [ ! -d "$prefix/Users/Shared/Riot Games/Riot Client.app/Contents/MacOS" ]; then
echo "The installer exited without installing the Riot Client. Its logs are in" >&2
+45 -38
View File
@@ -1,47 +1,54 @@
#!/usr/bin/env python3
"""Clear only a dead Darling server's stale PID marker before startup."""
"""Clear only a dead Darling server's stale PID marker and buffers before startup."""
import os
from pathlib import Path
import time
prefix = Path(os.environ.get('DPREFIX', str(Path.home() / '.darling')))
marker = prefix / '.init.pid'
try:
pid = int(marker.read_text().strip())
except (OSError, ValueError):
raise SystemExit(0)
if pid <= 0:
raise SystemExit(0)
status = Path('/proc') / str(pid) / 'status'
try:
state = next(line.split()[1] for line in status.read_text().splitlines() if line.startswith('State:'))
dead = state == 'Z'
except FileNotFoundError:
dead = True
except (OSError, StopIteration):
dead = False
if dead:
os.replace(marker, prefix / f'.init.pid.stale-{pid}-{time.time_ns()}')
print(f'Recovered stale Darling server marker for PID {pid}', flush=True)
# Clean up stale Riot temporary files and shared memory frames from previous crashes
try:
tmp_dir = prefix / 'private/tmp'
if tmp_dir.is_dir():
for f in tmp_dir.glob('.com.riotgames.*'):
server_running = False
if marker.exists():
try:
pid = int(marker.read_text().strip())
if pid > 0:
status = Path('/proc') / str(pid) / 'status'
try:
f.unlink(missing_ok=True)
except OSError:
pass
except OSError:
pass
state = next(line.split()[1] for line in status.read_text().splitlines() if line.startswith('State:'))
dead = state == 'Z'
except FileNotFoundError:
dead = True
except (OSError, StopIteration):
dead = False
try:
shm_dir = Path('/dev/shm')
if shm_dir.is_dir():
for f in shm_dir.glob('darling-*'):
try:
f.unlink(missing_ok=True)
except OSError:
pass
except OSError:
pass
if dead:
os.replace(marker, prefix / f'.init.pid.stale-{pid}-{time.time_ns()}')
print(f'Recovered stale Darling server marker for PID {pid}', flush=True)
else:
server_running = True
except (OSError, ValueError):
pass
# Only clean up stale Riot temporary files and shared memory frames if the server is NOT running
if not server_running:
try:
tmp_dir = prefix / 'private/tmp'
if tmp_dir.is_dir():
for f in tmp_dir.glob('.com.riotgames.*'):
try:
f.unlink(missing_ok=True)
except OSError:
pass
except OSError:
pass
try:
shm_dir = Path('/dev/shm')
if shm_dir.is_dir():
for f in shm_dir.glob('darling-*'):
try:
f.unlink(missing_ok=True)
except OSError:
pass
except OSError:
pass
+3 -5
View File
@@ -135,10 +135,8 @@ 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);
/* 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);
/* Wait for server consumption before reusing the segment on the next tick. */
XSync(f->display, False);
pthread_mutex_unlock(&f->render);
return result;
}
@@ -152,7 +150,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);
XFlush(f->display);
XSync(f->display, False);
pthread_mutex_unlock(&f->render);
return result;
}
+1 -1
View File
@@ -147,7 +147,7 @@ Type=Application
Name=League of Legends
GenericName=MOBA Game
Comment=Play League of Legends on Linux with darling-lol
Exec={run_script}
Exec="{run_script}"
Path={PROJECT_ROOT}
Icon=league-of-legends
Terminal=false