/* * 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 #include #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 (;;) { } }