libbgi: спрайтовый движок v2 + accel-блит/heal leaf'ы + noclip-путь
Спрайтовая графика поверх accel block-copy (docs/sprite-api-design.md): - Ядро блиттинга: leaf'ы _bgi_blit_rows_raw (dst фикс, только src-страйд) / _bgi_copy_rows_raw (getimage) / _bgi_heal_rows_raw (src==dst). DI один на спрайт (санкция: малый спрайт под одним DI аудио не рвёт); src[0]-фикс снят (точная MAME подавляет CPU-байт триггера записи — на железе перепроверить; для heal был избыточен и снят безусловно). - Общие bracket-free ядра _gfx_blit_full/_gfx_heal_full (полная ширина: клип по экрану + split >256 для putimage) + лин _gfx_blit_sprite/ _gfx_heal_sprite (кадр ≤64, без split, 8-бит w/h) + noclip-варианты (клип-кода нет → полный codegen-win). Имя *_full (не *_clip) — «clip» двусмысленно (sprite-ядра тоже клипуют; различитель — ширина/split). - Движок retained-модели <sprite.h>: sprite_init/update/flip + inline move/frame/show/hide/touch; drawn[2] per-page внутри структуры; кадр — двухпроходно heal ВСЕ -> блит ВСЕ под одной W3-скобкой/банком на проход. - Флаг gfx_sprite_clip(on/off): приложение, само следящее за границами, отключает клип (~+19% на анимации; диспетч пока через if — funcptr далее). - putsprite/movesprite/gfx_blit/putimage(COPY)/getimage переведены на ядро. Тесты: examples/balls (движок, дабл-буфер, boundary-тест клипа), tests/sprites (RAM PASS, клип 4 края, атлас), tests/blitw (trig-leak), tests/spriteclip (hardware-probe: железо НЕ режет за краем -> клип нужен), tests/blitperf, tests/gfxbanks. size-baseline обновлён (53 программы). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
PROJ_ROOT := $(abspath $(CURDIR)/../..)
|
||||
EXAMPLE := blitw
|
||||
EXTRA_FLAGS ?= --gfx 256 --memory small
|
||||
include $(PROJ_ROOT)/app.mk
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* blitw — программный регресс ядра блиттинга gfx_blit_part по ширинам.
|
||||
*
|
||||
* Репро артефакта tests/sprites (клипнутые шары w=12 рисуются со
|
||||
* сдвигом): блитим паттерн-образ 24×24 разными ширинами банком 0x50
|
||||
* (запись идёт и в ОЗУ-копию → getpixel читает ровно то, что записано)
|
||||
* и побайтно сверяем прямоугольник + рамку 1px вокруг (должна остаться
|
||||
* фоном). Вердикт по каждой ширине печатается на экране:
|
||||
* w=NN PASS | w=NN FAIL @x,y eXX gYY (exp/got первого расхождения)
|
||||
*
|
||||
* Запуск:
|
||||
* python3 toolchain/mame_interactive.py tests/blitw/blitw.exe \
|
||||
* --snap 14 --timeout 16
|
||||
*/
|
||||
|
||||
#include <graphics.h>
|
||||
#include <gfx.h>
|
||||
|
||||
#define IW 24
|
||||
#define IH 24
|
||||
#define TX 200 /* позиция тестового прямоугольника (правее текста) */
|
||||
#define TY 30
|
||||
|
||||
static uint8_t img[4 + IW * IH];
|
||||
static char msg[40];
|
||||
|
||||
static uint8_t pat(int x, int y)
|
||||
{
|
||||
return (uint8_t)(((x + 1) * (y + 3)) & 0x7F); /* != 0xFF, != 0 кроме редких */
|
||||
}
|
||||
|
||||
static void build_img(void)
|
||||
{
|
||||
uint8_t *p = img;
|
||||
int x, y;
|
||||
|
||||
*p++ = IW; *p++ = 0; *p++ = IH; *p++ = 0;
|
||||
for (y = 0; y < IH; y++)
|
||||
for (x = 0; x < IW; x++)
|
||||
*p++ = pat(x, y);
|
||||
}
|
||||
|
||||
static char hexd(uint8_t v)
|
||||
{
|
||||
v &= 15;
|
||||
return v < 10 ? '0' + v : 'A' + v - 10;
|
||||
}
|
||||
|
||||
/* Проверить блит шириной w в (tx,TY): весь rect = pat, рамка = 0. */
|
||||
static void check_w(int w, int tx, int ty, int row)
|
||||
{
|
||||
int x, y;
|
||||
uint8_t exp, got;
|
||||
uint8_t fail = 0;
|
||||
|
||||
/* фон под областью + рамкой */
|
||||
setfillstyle(SOLID_FILL, 0);
|
||||
bar(tx - 2, ty - 2, tx + w + 1, ty + IH + 1);
|
||||
|
||||
gfx_blit_part(tx, ty, img, 0, 0, w, IH);
|
||||
|
||||
for (y = -1; y <= IH && !fail; y++) {
|
||||
for (x = -1; x <= w && !fail; x++) {
|
||||
exp = (y >= 0 && y < IH && x >= 0 && x < w) ? pat(x, y) : 0;
|
||||
got = (uint8_t)getpixel(tx + x, ty + y);
|
||||
if (got != exp) {
|
||||
fail = 1;
|
||||
msg[0] = 'w'; msg[1] = '0' + w / 10; msg[2] = '0' + w % 10;
|
||||
msg[3] = ' '; msg[4] = 'F'; msg[5] = 'A'; msg[6] = 'I';
|
||||
msg[7] = 'L'; msg[8] = ' ';
|
||||
msg[9] = 'x'; msg[10] = (char)('0' + (x + 1) / 10);
|
||||
msg[11] = (char)('0' + (x + 1) % 10);
|
||||
msg[12] = 'y'; msg[13] = (char)('0' + (y + 1) / 10);
|
||||
msg[14] = (char)('0' + (y + 1) % 10);
|
||||
msg[15] = ' '; msg[16] = 'e'; msg[17] = hexd(exp >> 4);
|
||||
msg[18] = hexd(exp);
|
||||
msg[19] = ' '; msg[20] = 'g'; msg[21] = hexd(got >> 4);
|
||||
msg[22] = hexd(got);
|
||||
msg[23] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!fail) {
|
||||
msg[0] = 'w'; msg[1] = '0' + w / 10; msg[2] = '0' + w % 10;
|
||||
msg[3] = ' '; msg[4] = 'P'; msg[5] = 'A'; msg[6] = 'S';
|
||||
msg[7] = 'S'; msg[8] = 0;
|
||||
}
|
||||
outtextxy(4, 40 + row * 10, msg);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static const uint8_t widths[] = { 24, 16, 12, 8, 4, 2, 1 };
|
||||
uint8_t i;
|
||||
|
||||
build_img();
|
||||
initgraph();
|
||||
cleardevice();
|
||||
setcolor(WHITE);
|
||||
outtextxy(4, 4, "BLITW: gfx_blit_part width sweep");
|
||||
|
||||
for (i = 0; i < sizeof(widths); i++)
|
||||
check_w(widths[i], TX, TY, i);
|
||||
|
||||
/* и правый край, как в sprites: dst у конца строки page 0 */
|
||||
check_w(12, 308 - 12, TY, 7); /* dst близко к краю, но без клипа */
|
||||
|
||||
/* Регресс утечки CPU-байта write-триггера (см. шапку
|
||||
* _bgi_copy_rows_raw). Программно (getpixel = ОЗУ) утечка на MAME
|
||||
* 0.283 НЕ ловится: ОЗУ-ветка 0x58 пишет все байты, и burst
|
||||
* перезаписывает утечку в ОЗУ; жертвой остаётся только VRAM
|
||||
* (FF-скип). Поэтому проверка ВИЗУАЛЬНАЯ: блит образа с col0=0xFF
|
||||
* и последним столбцом YELLOW через 0x5C поверх ЗЕЛЁНОЙ плашки.
|
||||
* col0 (x=TX..) обязан остаться ЗЕЛЁНЫМ; до фикса он был YELLOW
|
||||
* (CPU-байт = последний байт burst-чтения). */
|
||||
{
|
||||
static uint8_t timg[4 + 16 * 8];
|
||||
uint8_t *p = timg;
|
||||
int x, y;
|
||||
|
||||
*p++ = 16; *p++ = 0; *p++ = 8; *p++ = 0;
|
||||
for (y = 0; y < 8; y++)
|
||||
for (x = 0; x < 16; x++)
|
||||
*p++ = (x == 0) ? 0xFF : (x == 15 ? YELLOW : LIGHTBLUE);
|
||||
|
||||
setfillstyle(SOLID_FILL, GREEN);
|
||||
bar(TX - 4, 150 - 4, TX + 19, 150 + 11);
|
||||
gfx_set_bank(GFX_BANK_SPRITE);
|
||||
gfx_blit(TX, 150, timg);
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
outtextxy(4, 40 + 8 * 10 + 4, "trig leak: col0 @200,150 green?");
|
||||
}
|
||||
|
||||
outtextxy(4, 40 + 9 * 10 + 6, "done");
|
||||
for (;;) { }
|
||||
}
|
||||
Reference in New Issue
Block a user