libbgi: FPS-делитель gfx_set_fps_div(n) поверх цепочки кадровых IRQ
Логический кадр = ровно n кадровых интервалов (1=50/2=25/3=~16.7 fps); при переполнении слота — выравнивание на ближайший фронт (без дрейфа фазы, в отличие от наивного «жди n фронтов»). Механика: фоновый счётчик _gfx_frame_tick инкрементит _gfx_frame_isr, поставленный в СВОЙ слот цепи (irq_chain_add); gfx_set_fps_div(1) снимает только этот слот (irq_chain_remove), не трогая хендлер приложения. gfx_wait_vsync: ветка n>=2 (счётчик + halt) перед лучевым поллингом; поллинг вынесен в static gfx_wait_vsync_beam (функция с хвостовым __asm не должна иметь переходов через asm — SDCC не эмитит эпилог-метку; ранний return делителя в чистом-C gfx_wait_vsync). Файлы: common/_gfx_fps_state.c (данные), _gfx_frame_isr.c (ISR), gfx_set_fps_div.c (сеттер, единственная ссылка на irq-механику → DCE). Работает tiny/big/huge (цепочка all-modes); small для мелких программ = EINVAL. Проверено MAME (tests/fpsdiv): n=1/2/3 → 20/40/60 кадров на 20 wait'ов (drift=0); n=2 с рендер-заглушкой ~1 кадр → период держится 2 (поглощение перерасхода, наивный путь дал бы ~60); huge идентично; small = EINVAL graceful. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+14
-6
@@ -27,12 +27,20 @@
|
||||
`irq_ctc_install` = EINVAL (нужна такая же W2-копия _irq_ctc_tramp);
|
||||
(б) small для мелких программ (BSS в W1) → irq_install EINVAL
|
||||
(safe; снять резервом area _IM2 в верхней W2).
|
||||
- [ ] **(2) FPS-делитель (frame pacing)** — gfx_set_fps_div(n): логический
|
||||
кадр = ровно n кадровых интервалов (50/25/16.7 fps), при
|
||||
переполнении слота — выравнивание на ближайший фронт; счётчик
|
||||
кадров через irq_chain_add(_gfx_frame_isr) (только tiny/big в
|
||||
первой версии). ПОЛНЫЙ ПЛАН: docs/sprite-api-design.md §9е
|
||||
(обсуждён 2026-07-14; ограничение EBUSY снято цепочкой).
|
||||
- [x] **(2) FPS-делитель (frame pacing)** — СДЕЛАНО 2026-07-15.
|
||||
gfx_set_fps_div(n): логический кадр = ровно n кадровых интервалов
|
||||
(1=50/2=25/3=~16.7 fps); при переполнении слота — выравнивание на
|
||||
ближайший фронт (без дрейфа фазы). Счётчик кадров _gfx_frame_tick
|
||||
через irq_chain_add(_gfx_frame_isr) — свой слот цепи (n<=1 снимает
|
||||
его через irq_chain_remove, не трогая хендлер приложения).
|
||||
gfx_wait_vsync: ветка n>=2 (счётчик+halt) перед лучевым поллингом.
|
||||
Файлы: common/_gfx_fps_state.c, _gfx_frame_isr.c, gfx_set_fps_div.c,
|
||||
правка gfx_wait_vsync.c. Работает tiny/big/huge (цепочка all-modes);
|
||||
small для мелких программ = EINVAL. ПРОВЕРЕНО MAME (tests/fpsdiv):
|
||||
n=1/2/3 → 20/40/60 кадров на 20 wait'ов (drift=0); n=2 с рендер-
|
||||
заглушкой ~1 кадр → период держится 2 (поглощение перерасхода,
|
||||
наивный путь дал бы ~60); huge идентично; small = EINVAL graceful.
|
||||
ПЛАН: docs/sprite-api-design.md §9е.
|
||||
- [ ] **П6/железо**: MAME-смоук всех тестов после libc-сплита (conio,
|
||||
ptime, stattest, mouse, gfx_demo/gfx_d16/gfx_text/gfx_mous —
|
||||
трогался asm акселератора); затем прогон на реальном Sprinter
|
||||
|
||||
@@ -25,6 +25,7 @@ errno 5966
|
||||
fbench 8085
|
||||
fdmax 6023
|
||||
filetest 10547
|
||||
fpsdiv 4870
|
||||
gets 509
|
||||
gfx_dbuf 5032
|
||||
gfx_demo 4103
|
||||
|
||||
|
@@ -842,7 +842,22 @@ putimage-заготовкой/маленьким bar.
|
||||
Тест: spranim T7 (порядок, слой поверх y, персистентный resort,
|
||||
LAYER-only).
|
||||
|
||||
## 9е. FPS-делитель — frame pacing (ПЛАН, обсуждён 2026-07-14, НЕ реализовано)
|
||||
## 9е. FPS-делитель — frame pacing (РЕАЛИЗОВАНО 2026-07-15, verified MAME)
|
||||
|
||||
**СТАТУС: сделано.** Файлы точно по плану ниже (common/_gfx_fps_state.c,
|
||||
_gfx_frame_isr.c, gfx_set_fps_div.c, ветка в gfx_wait_vsync.c). Через
|
||||
цепочку кадровых IRQ — работает tiny/big/huge (не только tiny/big);
|
||||
small для мелких программ = EINVAL. tests/fpsdiv: n=1/2/3 → ровно
|
||||
20/40/60 кадров на 20 wait'ов (drift=0); n=2 с рендер-заглушкой ~1 кадр
|
||||
→ период 2 (поглощение перерасхода, наивный путь дал бы ~60); huge
|
||||
идентично tiny; small = EINVAL graceful. Один нюанс реализации:
|
||||
лучевой поллинг вынесен в static gfx_wait_vsync_beam() (функция,
|
||||
кончающаяся непрозрачным __asm, не должна иметь переходов «через asm» —
|
||||
SDCC не эмитит эпилог-метку; ранний return делителя живёт в чистом-C
|
||||
gfx_wait_vsync). Ниже — исходный план (в силе).
|
||||
|
||||
---
|
||||
|
||||
|
||||
Цель (постановка пользователя): управляемые режимы 50/25/~16.7 fps —
|
||||
логический кадр занимает РОВНО n кадровых интервалов независимо от
|
||||
|
||||
Reference in New Issue
Block a user