Repository navigation
v0.0.193
rePIU v0.0.193
이전 릴리스 v0.0.192 이후의 변경입니다(Tasks 745–750). Linux x64에서 vsync를 켜도 노트와 BGA가
멈칫하지 않습니다. 드라이버가 vsync를 거부하면 엔진이 주사율에 맞춰 swap을 직접 맞추고, MP3 재생 시계는
장치의 pull 지터에 흔들리지 않으며, swap을 기다리는 동안에도 타이머 ISR이 돕니다. 인자를 주고 실행할 때도
cfg/repiu.ini가 적용됩니다. 사용자가 WSLg(wayland, 진짜 vsync)에서 플레이로 확인했습니다.
숫자로 (pumpitea 곡 구간, 곡 중 입력 있는 62초 플레이, WSL Linux x64 Release)
| v0.0.192 | v0.0.193 | |
|---|---|---|
swap_interval = 1의 fps (llvmpipe가 vsync 거부) |
58~98 | 59.9~60.1 |
| MP3 frame-sync 토글 간격(26.1 ms여야 함) | 16~35 ms | 24~27 ms (98%) |
| 게스트가 토글을 보는 지연, 60 Hz 대기에서 | 0~16 ms 균등 | 0~4 ms |
| 게스트의 곡 위치 걸음, 60 Hz 대기에서 | 16 ms / 33 ms 쌍봉 | 25 ms 중심 (21~31) |
| 페이싱 attract 14초의 tick 폐기 | 936 | 62 |
| 25 ms 초과 프레임(곡 구간) | — | 0 |
vsync off의 자유 실행은 이전에도 관측 지연 0~7 ms였고 이번에도 같습니다. 달라진 것은 vsync를 켠 실행이
그와 같아졌다는 점입니다.
고친 것
드라이버가 vsync를 거부할 때의 swap 페이싱 (Task 745) — WSLg의 llvmpipe GL은
SDL_GL_SetSwapInterval(1)을 거부합니다("That operation is not supported"). 거부되면 엔진이
grBufferSwap 뒤에서 디스플레이 주사율 기준 마감까지 기다립니다. 마감은 누적되어 평균 속도가 정확하고,
한 주기 이상 밀리면 다시 맞춥니다. 최종 보고의 Glide swap pacing … 두 줄이 활성 여부·주기·거부 사유와
지터(late, resyncs, oversleep)를 말합니다.
인자 실행도 cfg/repiu.ini를 읽습니다 (Task 746) — repiu pumpitea처럼 런처를 거치지 않는 실행도
같은 파일을 먼저 읽어 적용합니다. 같은 뜻의 환경 변수가 있으면 환경 변수가 이깁니다. 로그의 Launcher settings read from … 줄이 값의 출처를 말합니다.
HLE 재진입 뒤의 tick 주입 (Task 747) — Linux x64는 ISR의 iret·out·cli를 처리한 뒤 밀린 tick을
주입하지 않아, 긴 게이트 뒤에 프레임당 두 개만 빠지고 backlog(64)가 넘쳤습니다. legacy 체인과 같은 주입
호출을 넣어 iret 직후 중첩 없이 빠집니다.
MP3 재생 시계가 자유 진행합니다 (Task 749) — 이전 시계는 장치가 768프레임을 가져갈 때마다 선을 직전
계단에서 다시 그려, pull 시각의 몇 ms 지터가 12 ms 점프와 정지가 됐습니다. 이제 자기 이전 값에서 PCM
속도로 진행하고, 가져간 count에서 장치 버퍼 절반을 뺀 목표까지 4초 시정수(±2%)로 맞춥니다. 가져간 count를
넘지 않고 뒤로 가지 않는 불변식은 그대로입니다.
swap을 기다리는 동안에도 타이머 tick (Task 750, Linux x64) — grBufferSwap 게이트 안에서는 게스트
코드가 돌지 않아 타이머 ISR도 멈췄습니다. 이제 게이트가 present를 호스트 스레드에 넘기고 기다리면서, 밀린
tick을 "게이트에 도달한 call 직전에 온 인터럽트"로 주입합니다. ISR의 iret가 call을 다시 실행해
게이트로 돌아오고, present가 끝났을 때만 게이트가 반환합니다. 실제 기계가 vblank 대기 중에도 IRQ0을 받는
것과 같습니다. tick을 무장하는 코드도 호스트 폴 루프 전용에서 게스트 대기 루프가 함께 부르는 호출로
바뀌었습니다.
새 스위치와 진단 (설정하지 않으면 기본 동작)
| 변수 / 출력 | 내용 |
|---|---|
Glide swap pacing active/refresh-hz/period-us/paced-swaps/slept-ms/refusal (최종 보고) |
페이싱 활성 여부와 거부 사유 |
Glide swap pacing late-swaps/late-max-us/resyncs/oversleep>1ms/oversleep-max-us (최종 보고) |
페이서 지터 |
Glide swap wait ticks swaps/injections (최종 보고) |
대기 중 tick을 전달한 swap 수와 주입 수 |
REPIU_GLIDE_SWAP_WAIT_TICKS=0 |
대기 중 tick 전달을 끔(Linux x64 전용 기능, 기본 켜짐) |
REPIU_GLIDE_SWAP_WAIT_LOG=1 |
tick을 전달하지 못한 대기를 처음 몇 번 찍음 |
REPIU_PIU10_MP3_POSITION_TRACE=1 |
토글마다, 게스트가 새 값을 본 읽기마다 [repiu-mp3-pos] toggle|seen … |
REPIU_GLIDE_LONG_FRAME_LOG=1 (큰 값은 µs 문턱) |
주기 1.5배를 넘긴 프레임을 sleep/guest/present로 분해 |
REPIU_INPUT_SCRIPT=<파일> |
<ms> <키 이름> [hold ms] 줄을 SDL 키 이벤트로 넣는 스크립트 키보드. 예: scripts/input_scripts/pumpitea_play.txt, pumpitea_play_steps.txt |
REPIU_DOS_ASSET_TRACE=all |
자산 트레이스의 상한(열기 200·읽기 120·seek 120)을 없앰 |
알려진 것
- wayland 드라이버가 진짜 vsync를 받습니다. WSLg는 소켓이
/mnt/wslg/runtime-dir에 있으므로
XDG_RUNTIME_DIR=/mnt/wslg/runtime-dir SDL_VIDEO_DRIVER=wayland로 실행합니다. 이전 기록의 "wayland
드라이버는 창을 못 연다"는 이 경로 문제였습니다. - wayland로 시작할 때 6회 중 2회, 4초부터 tick 주입이 초당 18,000으로 치솟다가 13초에 게스트 스택이 넘쳐
죽었습니다. 최근 실행에서는 나오지 않았고 원인은 조사하지 않았습니다. - 대기 중 tick 전달은 Linux x64 전용입니다. Win32에서 켜면 첫 주입 뒤 폴트 없이 멈춰 제공하지
않습니다. Win32의 vsync도 같은 게이트 대기를 하므로 같은 관측 지연이 있을 것입니다. - Win32 pumpitea는 15초에 tick 380개를 버립니다(vsync on/off 같음). 이번 변경과 무관하며 미조사입니다.
- 입력 없는 플레이는 곡 14초쯤 게이지가 비어 실패 연출로 들어가고, 그때의 BGA 로드(
HEYMAN.DAT등)가
80~340 ms 프레임을 만듭니다. 계측할 때 곡 중 멈칫으로 오인하지 않도록 입력 스크립트를 쓰십시오. - 호출부가
call rel32가 아닌 게임은 대기 중 tick을 받지 못하고 이전처럼 기다립니다.
rePIU v0.0.193
Changes since v0.0.192 (Tasks 745–750). On Linux x64 the arrows and the BGA no longer hitch with
vsync on. When the driver refuses vsync the engine paces the swaps at the refresh rate, the MP3
playback clock no longer follows the device's pull jitter, and the timer ISR runs while a swap is
waited out. A run started with arguments applies cfg/repiu.ini too. Confirmed by the user playing on
WSLg (wayland, real vsync).
In numbers (pumpitea inside a song, 62 s plays with in-song input, WSL Linux x64 Release)
| v0.0.192 | v0.0.193 | |
|---|---|---|
fps at swap_interval = 1 (llvmpipe refuses vsync) |
58–98 | 59.9–60.1 |
| MP3 frame-sync toggle interval (should be 26.1 ms) | 16–35 ms | 24–27 ms (98%) |
| Guest's delay in seeing a toggle, under a 60 Hz wait | uniform 0–16 ms | 0–4 ms |
| Guest's song position step, under a 60 Hz wait | 16 ms / 33 ms bimodal | centred on 25 ms (21–31) |
| Ticks dropped in a paced 14 s attract | 936 | 62 |
| Frames over 25 ms (inside the song) | — | 0 |
Free-running with vsync off already observed within 0–7 ms and still does; what changed is that a run
with vsync on now matches it.
Fixed
Swap pacing when the driver refuses vsync (Task 745) — WSLg's llvmpipe GL refuses
SDL_GL_SetSwapInterval(1) ("That operation is not supported"). When refused, the engine waits after
grBufferSwap until a deadline derived from the display's refresh rate. Deadlines accumulate, so the
average rate is exact, and a deadline more than a period behind is resynchronised. The final report's
two Glide swap pacing … lines give the state, the period, the refusal and the jitter (late, resyncs,
oversleep).
Argument runs read cfg/repiu.ini (Task 746) — a run that skips the launcher, such as
repiu pumpitea, reads and applies the same file first; an environment variable of the same meaning
still wins. The log's Launcher settings read from … line says where each value came from.
Tick injection after an HLE reentry (Task 747) — Linux x64 handled the ISR's iret, out and
cli without attempting an injection afterwards, so after a long gate the owed ticks drained two a
frame and the backlog (64) overflowed. The legacy chain's injection call is now there too, draining
right after iret without nesting.
The MP3 playback clock free-runs (Task 749) — the previous clock restarted its line at the
previous step every time the device took 768 frames, so a few ms of pull jitter became 12 ms jumps and
stalls. It now advances from its own previous value at the PCM rate and slews, with a four second time
constant (±2%), to the pulled count less half a device buffer. It still never passes the pulled count
and never runs backwards.
Timer ticks while a swap is waited out (Task 750, Linux x64) — no guest code ran inside the
grBufferSwap gate, so the timer ISR stopped too. The gate now hands the present to the host thread
and waits, injecting an owed tick as "an interrupt that arrived just before the call that reached
the gate": the ISR's iret runs the call again and returns to the gate, which returns to its caller
only when the present is done, as the real machine takes IRQ0 during its vblank wait. The code that
arms ticks moved from the host poll loop into a call the guest's wait loop makes too.
New switches and diagnostics (default behaviour when unset)
| Variable / output | Meaning |
|---|---|
Glide swap pacing active/refresh-hz/period-us/paced-swaps/slept-ms/refusal (final report) |
whether pacing is active, and the refusal |
Glide swap pacing late-swaps/late-max-us/resyncs/oversleep>1ms/oversleep-max-us (final report) |
the pacer's jitter |
Glide swap wait ticks swaps/injections (final report) |
swaps waited out with ticks delivered, and the injections |
REPIU_GLIDE_SWAP_WAIT_TICKS=0 |
turns the ticks during the wait off (a Linux x64 feature, on by default) |
REPIU_GLIDE_SWAP_WAIT_LOG=1 |
names the first few waits that could not deliver a tick |
REPIU_PIU10_MP3_POSITION_TRACE=1 |
[repiu-mp3-pos] toggle|seen … per toggle and per guest read that first sees the new value |
REPIU_GLIDE_LONG_FRAME_LOG=1 (a larger value is a µs threshold) |
splits a frame over one and a half periods into sleep, guest and present |
REPIU_INPUT_SCRIPT=<file> |
a scripted keyboard pushing <ms> <key name> [hold ms] lines as SDL key events; see scripts/input_scripts/pumpitea_play.txt and pumpitea_play_steps.txt |
REPIU_DOS_ASSET_TRACE=all |
lifts the asset trace's caps (200 opens, 120 reads, 120 seeks) |
Known
- The wayland driver takes real vsync. WSLg keeps its socket in
/mnt/wslg/runtime-dir, so run
withXDG_RUNTIME_DIR=/mnt/wslg/runtime-dir SDL_VIDEO_DRIVER=wayland. The earlier note that the
wayland driver opens no window was this path. - Starting under wayland, 2 of 6 runs had the tick injection climb to 18,000 a second from 4 s and
overflow the guest stack at 13 s. It has not appeared in recent runs and is not investigated. - Ticks during the wait are Linux x64 only. Forced on under Win32 the run stalls after the first
injection, without a fault, so it is not offered there; Win32's vsync waits in the same gate and is
expected to have the same observation delay. - Win32 pumpitea drops 380 ticks in 15 s, vsync on or off. Unrelated to this release and not
investigated. - A play without input empties its gauge about 14 s into the song and enters the fail sequence, whose
BGA loads (HEYMAN.DATand others) make 80–340 ms frames. Use an input script when measuring, so
they are not mistaken for in-song hitches. - A game whose call site is not
call rel32gets no ticks during the wait and waits as before.