gfx_scroll_v: колоночный accel-проход без буфера-посредника + тест scroll

Вертикальный скролл перестал ходить через строку-буфер на стеке: колонку
читаем с Port_Y=ys, пишем с Port_Y=yd, а STOP между read- и write-триггером
делает промежуточный OUT Port_Y безопасным.  Один проход вместо
grab→blit-через-буфер.

Справочник libc приведён в соответствие (там же строка про новую точку
входа cbl_open_silence).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 21:59:28 +03:00
parent 3ea4546656
commit e2730f78e0
5 changed files with 287 additions and 27 deletions
+73 -13
View File
@@ -27,18 +27,73 @@
#include "../_bgi.h"
void gfx_scroll_h(const gfx_rect_t *area, int16_t dx, gfx_rect_t *dirty) {
uint8_t saved = gfx_get_bank();
uint16_t adx = (dx < 0) ? (uint16_t)(-dx) : (uint16_t)dx;
/* src-строка стартует правее на |dx| при сдвиге влево, dst — правее
* на dx при сдвиге вправо; так оба края остаются внутри area. */
uint16_t src_x = area->x + ((dx < 0) ? adx : 0);
uint16_t dst_x = area->x + ((dx > 0) ? adx : 0);
uint16_t w = area->w - adx; /* байт (пикселей) в строке */
uint8_t h = (uint8_t)area->h; /* строк (256 => 0 = 256 у leaf) */
#ifdef GFX_NOCHECK
uint8_t saved = gfx_get_bank();
uint16_t adx = (dx < 0) ? (uint16_t)(-dx) : (uint16_t)dx;
uint16_t src_x = area->x + ((dx < 0) ? adx : 0);
uint16_t dst_x = area->x + ((dx > 0) ? adx : 0);
uint16_t w = area->w - adx;
uint8_t h = (uint8_t)area->h;
uint16_t src = _gfx_addr_shadow_base + src_x;
uint16_t dst = _gfx_addr_base + dst_x;
gfx_set_bank(GFX_BANK_NORMAL);
_bgi_begin();
while (w) {
uint8_t cw = (w > 255) ? 255 : (uint8_t)w;
_bgi_scroll_rows_raw(src, dst, cw, h, (uint8_t)area->y);
src += cw; dst += cw; w -= cw;
}
_bgi_end();
gfx_set_bank(saved);
if (dirty) {
dirty->x = (dx >= 0) ? area->x : (int16_t)(area->x + area->w - adx);
dirty->y = area->y; dirty->w = adx; dirty->h = area->h;
}
#else
int16_t x, y;
uint16_t aw, ah, cut, adx;
uint8_t saved, h;
uint16_t src_x, dst_x, w, src, dst;
if (!area) return;
x = area->x; y = area->y; aw = area->w; ah = area->h;
if (!aw || !ah) goto empty;
/* Raw-leaf не клипит. Нормализуем область до экрана и не допускаем
* 16-битного underflow в area->w-|dx|. */
if (x < 0) {
cut = (uint16_t)(-x);
if (cut >= aw) goto empty;
aw -= cut; x = 0;
}
if (y < 0) {
cut = (uint16_t)(-y);
if (cut >= ah) goto empty;
ah -= cut; y = 0;
}
if (x >= GFX_WIDTH || y >= GFX_HEIGHT) goto empty;
if (aw > (uint16_t)(GFX_WIDTH - x)) aw = (uint16_t)(GFX_WIDTH - x);
if (ah > (uint16_t)(GFX_HEIGHT - y)) ah = (uint16_t)(GFX_HEIGHT - y);
/* Сначала сравнение со знаком: так не вычисляем -INT16_MIN. */
if (dx >= (int16_t)aw || dx <= -(int16_t)aw) {
if (dirty) { dirty->x=x; dirty->y=y; dirty->w=aw; dirty->h=ah; }
return;
}
adx = (dx < 0) ? (uint16_t)(-dx) : (uint16_t)dx;
saved = gfx_get_bank();
/* src-строка стартует правее на |dx| при сдвиге влево, dst — правее
* на dx при сдвиге вправо; так оба края остаются внутри area. */
src_x = (uint16_t)x + ((dx < 0) ? adx : 0);
dst_x = (uint16_t)x + ((dx > 0) ? adx : 0);
w = aw - adx;
h = (uint8_t)ah; /* 256 => 0 у leaf */
src = _gfx_addr_shadow_base + src_x;
dst = _gfx_addr_base + dst_x;
gfx_set_bank(GFX_BANK_NORMAL);
_bgi_begin();
@@ -54,7 +109,7 @@ void gfx_scroll_h(const gfx_rect_t *area, int16_t dx, gfx_rect_t *dirty) {
// src += 256; dst += 256;
// w -= (w > 256) ? 256 : w;
uint8_t cw = (w > 255) ? 255 : (uint8_t)w; /* 0 => 256 */
_bgi_scroll_rows_raw(src, dst, cw, h, (uint8_t)area->y);
_bgi_scroll_rows_raw(src, dst, cw, h, (uint8_t)y);
src += cw; dst += cw; w -= cw;
}
@@ -62,9 +117,14 @@ void gfx_scroll_h(const gfx_rect_t *area, int16_t dx, gfx_rect_t *dirty) {
gfx_set_bank(saved);
if (dirty) {
dirty->x = (dx >= 0) ? area->x : (int16_t)(area->x + area->w - adx);
dirty->y = area->y;
dirty->x = (dx >= 0) ? x : (int16_t)(x + aw - adx);
dirty->y = y;
dirty->w = adx;
dirty->h = area->h;
dirty->h = ah;
}
return;
empty:
if (dirty) { dirty->x=0; dirty->y=0; dirty->w=0; dirty->h=0; }
#endif
}
+68 -11
View File
@@ -24,20 +24,72 @@
#include "../_bgi.h"
void gfx_scroll_v(const gfx_rect_t *area, int16_t dy, gfx_rect_t *dirty) {
#ifdef GFX_NOCHECK
uint8_t saved = gfx_get_bank();
uint16_t ady = (dy < 0) ? (uint16_t)(-dy) : (uint16_t)dy;
uint8_t ys = (uint8_t)(area->y + ((dy < 0) ? ady : 0));
uint8_t yd = (uint8_t)(area->y + ((dy > 0) ? ady : 0));
uint16_t hb = area->h - ady;
uint8_t saved = gfx_get_bank();
uint16_t ady = (dy < 0) ? (uint16_t)(-dy) : (uint16_t)dy;
if (hb) {
uint8_t hblk = (uint8_t)hb;
uint16_t w = area->w;
uint16_t src = _gfx_addr_shadow_base + area->x;
uint16_t dst = _gfx_addr_base + area->x;
gfx_set_bank(GFX_BANK_NORMAL);
_bgi_begin();
while (w) {
uint8_t cw = (w > 255) ? 255 : (uint8_t)w;
_bgi_scroll_cols_raw(src, dst, cw, hblk, ys, yd);
src += cw; dst += cw; w -= cw;
}
_bgi_end();
gfx_set_bank(saved);
}
if (dirty) {
dirty->x = area->x;
dirty->y = (dy >= 0) ? area->y : (int16_t)(area->y + area->h - ady);
dirty->w = area->w; dirty->h = ady;
}
#else
int16_t x, y;
uint16_t aw, ah, cut, ady, hb;
uint8_t saved, ys, yd;
if (!area) return;
x = area->x; y = area->y; aw = area->w; ah = area->h;
if (!aw || !ah) goto empty;
if (x < 0) {
cut = (uint16_t)(-x);
if (cut >= aw) goto empty;
aw -= cut; x = 0;
}
if (y < 0) {
cut = (uint16_t)(-y);
if (cut >= ah) goto empty;
ah -= cut; y = 0;
}
if (x >= GFX_WIDTH || y >= GFX_HEIGHT) goto empty;
if (aw > (uint16_t)(GFX_WIDTH - x)) aw = (uint16_t)(GFX_WIDTH - x);
if (ah > (uint16_t)(GFX_HEIGHT - y)) ah = (uint16_t)(GFX_HEIGHT - y);
if (dy >= (int16_t)ah || dy <= -(int16_t)ah) {
if (dirty) { dirty->x=x; dirty->y=y; dirty->w=aw; dirty->h=ah; }
return;
}
ady = (dy < 0) ? (uint16_t)(-dy) : (uint16_t)dy;
saved = gfx_get_bank();
/* Строку чтения (ys) сдвигаем вниз на |dy| при сдвиге вверх, строку
* записи (yd) — вниз на dy при сдвиге вниз; края в пределах area. */
uint8_t ys = (uint8_t)(area->y + ((dy < 0) ? ady : 0));
uint8_t yd = (uint8_t)(area->y + ((dy > 0) ? ady : 0));
uint16_t hb = area->h - ady; /* строк к переносу (≤256) */
ys = (uint8_t)(y + ((dy < 0) ? ady : 0));
yd = (uint8_t)(y + ((dy > 0) ? ady : 0));
hb = ah - ady;
if (hb) { /* 0 = переносить нечего */
uint8_t hblk = (uint8_t)hb; /* размер accel-блока: 256 => 0 */
uint16_t w = area->w;
uint16_t src = _gfx_addr_shadow_base + area->x;
uint16_t dst = _gfx_addr_base + area->x;
uint16_t w = aw;
uint16_t src = _gfx_addr_shadow_base + (uint16_t)x;
uint16_t dst = _gfx_addr_base + (uint16_t)x;
gfx_set_bank(GFX_BANK_NORMAL);
_bgi_begin();
@@ -55,9 +107,14 @@ void gfx_scroll_v(const gfx_rect_t *area, int16_t dy, gfx_rect_t *dirty) {
}
if (dirty) {
dirty->x = area->x;
dirty->y = (dy >= 0) ? area->y : (int16_t)(area->y + area->h - ady);
dirty->w = area->w;
dirty->x = x;
dirty->y = (dy >= 0) ? y : (int16_t)(y + ah - ady);
dirty->w = aw;
dirty->h = ady;
}
return;
empty:
if (dirty) { dirty->x=0; dirty->y=0; dirty->w=0; dirty->h=0; }
#endif
}