Files
Sprinter-SDCC/docs/accel-fill-budget.md
T
snark13 5f0c46f0ea docs: идея span-примитивов для узких прямоугольников (TODO + fill-budget)
При узкой стороне <= 8 линий chunked-rectfill проигрывает циклу
_bgi_hspan_raw/_bgi_vspan_raw (подготовка ~340Т впустую, break-even
n~9): либо fast-path в диспетчере, либо рецепт для пользователя —
решать по профилю.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 18:02:16 +03:00

121 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Акселератор: бюджет тактов и размеров chunked-заливок (rectfill/clear)
2026-07-10, после рефактора 2c414da (chunked-заливки v3 на мульти-триггере
акселератора). Семантика FSM акселератора — memory/accel_multitrigger_fill,
регресс-тест — tests/accfill. Такты — стандартные Z80; пересчёт в мкс —
для 21 МГц без учёта wait-state'ов видеопамяти.
## Архитектура v3 (что считаем)
`_gfx_rectvfill256` / `_gfx_recthfill256`: заливка чанками ≤16 линий на одну
DI/EI-скобку. В скобке размер блока армируется один раз; на линию — OUT
Port_Y (при выключенном акселераторе) + 1 опкод режима (LD E,E / LD C,C) +
выстрел + LD B,B. Счётчик чанков precompute'ится один раз на входе в
байт-регистр E (`n>>4`), хвост `n&15` SMC-патчится в отдельную хвостовую
скобку со своим армированием (в окне EI между чанками CBL-ISR армирует
акселератор своим размером блока — поэтому армирование в каждой скобке).
## Бюджет v3
### 1) Подготовка — один раз на прямоугольник (~325–340Т)
| блок | тактов |
|-------------------------------------------------------|---------|
| пролог: push ix / ld ix,#0 / add ix,sp + база+x + цвет | 102 |
| SMC размера в обе скобки (19+13+13) | 45 |
| precompute: хвост n&15 → SMC + чанки n>>4 → E | 108118 |
| проверка «есть ли полные чанки» | 1520 |
| эпилог: pop ix / 3×pop / inc sp / jp (hl) | 54 |
### 2) На блок 16 линий — 46Т
ld b,#16 (7) + di (4) + арм ld d,d / ld a,#n / ld b,b (15) + ei (4) +
dec e / jr nz (16) = 46Т ≈ 2.9Т/линию. Хвостовая скобка ≈ 45Т (заход
22 + арм 23).
### 3) На линию — 53Т (vertical) / 51Т (horizontal)
ld a,d (4) + out (11) + режим (4) + ld a,c (4) + ld (hl),a (7) +
ld b,b (4) + inc hl (6) / inc d (4) + djnz (13).
**Формула:** T(n) ≈ 340 + 46·⌈n/16⌉ + 53·n (vertical; horizontal 51·n).
## Альтернативы: каждая линия в своей DI/EI-скобке
**А — байтовый счётчик в B + djnz** (арм на линию, всё в одном цикле):
подготовка ~210Т, линия 72Т (h) / 74Т (v). Ограничение: счётчик ≤ 256 —
для vertical с w до 320 нужен двухпроходный костыль (~+10 байт).
Бонус: DI-окно = 1 линия (≤37 мкс) — минимальная латентность прерываний.
**Б — 16-бит счётчик в IX-слотах** (стиль per-line v1, без call):
подготовка ~190Т, линия ~206Т (135Т из них — декремент+проверка 16-бит
числа через 19Т-обращения к IX-слотам).
### Тотализатор (vertical, тактов на прямоугольник n линий)
| линий | v3 | А (djnz) | Б (IX) |
|-------|---------|-----------|----------|
| 1 | ~420 | **~280** | ~395 |
| 4 | ~580 | **~500** | ~1015 |
| 8 | ~790 | **~785** | ~1840 |
| 9 | ~845 | ~855 | ~2045 |
| 16 | ~1215 | ~1365 | ~3490 |
| 64 | ~3895 | ~4820 | ~13 375 |
| 256 | ~14 620 | ~18 640 | ~52 930 |
**Break-even v3 против А: n ≈ 9 линий** (340+53n+2.9n = 210+72n → n≈8.3).
При n ≤ 8 простейший А быстрее (максимум выигрыша +140Т ≈ 6.7 мкс на n=1 —
precompute уходит впустую); при n ≥ 9 v3 впереди, дальше ~19Т/линию (~26%
CPU-оверхеда; полный экран — экономия ~4000Т ≈ 190 мкс).
Б проигрывает v3 уже с n = 2 — от него и уходили.
## Размер кода (активные инструкции, на один leaf)
| вариант | байт | разбивка |
|--------------|--------|-------------------------------------------------|
| v3 (текущий) | ~107 | пролог 18 + SMC 9 + precompute 26 + вход 4 + чанк-цикл 21 + хвост 22 + эпилог 7 |
| А (djnz) | ~5363 | пролог 18 + SMC 6 + счётчик 7 + линия 15 + эпилог 7 (+~10 двухпроходность vertical) |
| Б (IX) | ~70 | пролог 18 + SMC 6 + цикл 39 + эпилог 7 |
Диспетчер `_gfx_rectfill256` ≈ 40 байт (проверка ориентации 160–245Т,
break-even |wh| ≥ ~4 линии — при известной форме звать leaf напрямую).
Переход пары leaf'ов на А дал бы ~−100 байт на программу ценой −26%
скорости на n ≥ 9.
**Решение: оставлена v3** — в графическом коде такты дороже сотни байт;
для узких прямоугольников (≤8 линий) есть span-примитивы
_bgi_hspan_raw/_bgi_vspan_raw (одна линия одной скобкой без precompute).
## Идеи (не реализовано)
- **Отказаться от поддержки сторон > 256 точек.** Сейчас vertical тащит
ветку «старший байт w = +16 чанков» (precompute) ради 257..320; если
ограничить контракт стороной ≤ 256 и оставить пользователю выводить
широкие прямоугольники в два приёма самому — упрощается precompute
(~−15Т подготовки, −5..8 байт), исчезает UB-зона w>511, контракты
обеих leaf-функций становятся симметричными. Цена: bar() на полную
ширину экрана обязан сам разбить вызов на два (или это делает
диспетчер — тогда экономии в диспетчерном пути нет, только в прямых
вызовах leaf'ов).
- **Два варианта рисования + переключение опцией сборки.** Реализовать
оба: поблочный (v3, быстрый при n ≥ 9, DI-окно ≤0.7 мс) и построчный
(А: per-line di/ei + djnz, 100 байт на пару leaf'ов, быстрый при
n ≤ 8, DI-окно = 1 линия ≤37 мкс — идеально при активном CBL) — и
выбирать опцией сборки в духе существующего GFX_NOCHECK / safe-fast
вариантов libbgi. Кандидат для size-critical сборок (small 32КБ,
как mdview2) и для программ с жёсткими требованиями к латентности
прерываний.
- **Span-примитивы для узких прямоугольников (узкая сторона ≤ 8).**
Break-even n≈9 означает: прямоугольник в 2..8 линий по узкой стороне
дешевле нарисовать циклом готовых span-примитивов
(_bgi_hspan_raw/_bgi_vspan_raw — одна линия одной скобкой, без
подготовки/precompute), чем через rectfill, где ~340Т подготовки
уходят впустую. Варианты: fast-path в диспетчере _gfx_rectfill256
(«узкая сторона ≤ 8 → цикл span'ов»; удорожает проверку диспетчера
на ~20-30Т) или оставить на усмотрение пользователя, задокументировав
рецепт. Делать по результатам профиля — если такие прямоугольники
встречаются в горячем коде (рамки, тонкие полосы, разделители).
Продублировано в docs/TODO.md (GFX: оптимизации).