mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-04 04:06:06 -05:00
wip: use a sliding window instead of memmove() to scroll
Instead of memmoving a large amount of data on every scroll, use a sliding window. That is, each time we scroll, we offset origin.
This commit is contained in:
parent
9e3b8ab3ff
commit
d70956da08
7 changed files with 140 additions and 108 deletions
2
csi.c
2
csi.c
|
|
@ -280,7 +280,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
i == term->vt.params.idx - 1 ? "" : ";");
|
||||
}
|
||||
|
||||
c += snprintf(&log[c], sizeof(log) - c, "%c (%zu parameters)",
|
||||
c += snprintf(&log[c], sizeof(log) - c, "%c (%d parameters)",
|
||||
final, term->vt.params.idx);
|
||||
LOG_DBG("%s", log);
|
||||
#endif
|
||||
|
|
|
|||
34
grid.c
34
grid.c
|
|
@ -6,3 +6,37 @@
|
|||
#define LOG_MODULE "grid"
|
||||
#define LOG_ENABLE_DBG 1
|
||||
#include "log.h"
|
||||
|
||||
struct cell *
|
||||
grid_get_range(struct grid *grid, size_t start, size_t *length)
|
||||
{
|
||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||
assert(*length <= grid->size);
|
||||
|
||||
size_t real_start = (grid->offset + start) % grid->size;
|
||||
assert(real_start < grid->size);
|
||||
|
||||
*length = min(*length, grid->size - real_start);
|
||||
assert(real_start + *length <= grid->size);
|
||||
|
||||
return &grid->cells[real_start];
|
||||
#undef min
|
||||
}
|
||||
|
||||
void
|
||||
grid_memset(struct grid *grid, size_t start, int c, size_t length)
|
||||
{
|
||||
size_t left = length;
|
||||
while (left > 0) {
|
||||
size_t count = left;
|
||||
struct cell *cells = grid_get_range(grid, start, &count);
|
||||
|
||||
assert(count > 0);
|
||||
assert(count <= left);
|
||||
|
||||
memset(cells, c, count * sizeof(cells[0]));
|
||||
|
||||
left -= count;
|
||||
start += count;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4
grid.h
4
grid.h
|
|
@ -1,3 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include "terminal.h"
|
||||
|
||||
struct cell *grid_get_range(struct grid *grid, size_t start, size_t *length);
|
||||
void grid_memset(struct grid *grid, size_t start, int c, size_t length);
|
||||
|
|
|
|||
66
main.c
66
main.c
|
|
@ -79,24 +79,42 @@ attrs_to_font(struct context *c, const struct attributes *attrs)
|
|||
static void
|
||||
grid_render_update(struct context *c, struct buffer *buf, const struct damage *dmg)
|
||||
{
|
||||
LOG_DBG("damage: UPDATE: %d -> %d",
|
||||
dmg->range.start, dmg->range.start + dmg->range.length);
|
||||
LOG_DBG("damage: UPDATE: %d -> %d (offset = %d)",
|
||||
(dmg->range.start - c->term.grid->offset) % c->term.grid->size,
|
||||
(dmg->range.start - c->term.grid->offset) % c->term.grid->size + dmg->range.length,
|
||||
c->term.grid->offset);
|
||||
|
||||
int start = dmg->range.start;
|
||||
int length = dmg->range.length;
|
||||
|
||||
if (start < c->term.grid->offset) {
|
||||
int end = start + length;
|
||||
if (end >= c->term.grid->offset) {
|
||||
start = c->term.grid->offset;
|
||||
length = end - start;
|
||||
} else
|
||||
return;
|
||||
}
|
||||
|
||||
const int cols = c->term.cols;
|
||||
|
||||
for (int linear_cursor = dmg->range.start,
|
||||
row = dmg->range.start / cols,
|
||||
col = dmg->range.start % cols;
|
||||
linear_cursor < dmg->range.start + dmg->range.length;
|
||||
for (int linear_cursor = start,
|
||||
row = ((start - c->term.grid->offset) % c->term.grid->size) / cols,
|
||||
col = ((start - c->term.grid->offset) % c->term.grid->size) % cols;
|
||||
linear_cursor < start + length;
|
||||
linear_cursor++,
|
||||
//col = (col + 1) % cols,
|
||||
col = col + 1 >= c->term.cols ? 0 : col + 1,
|
||||
row += col == 0 ? 1 : 0)
|
||||
{
|
||||
|
||||
//LOG_DBG("UPDATE: %d (%dx%d)", linear_cursor, row, col);
|
||||
|
||||
const struct cell *cell = &c->term.grid->cells[linear_cursor];
|
||||
bool has_cursor = c->term.cursor.linear == linear_cursor;
|
||||
//assert(linear_cursor < c->term.grid->size);
|
||||
const struct cell *cell = &c->term.grid->cells[linear_cursor % c->term.grid->size];
|
||||
|
||||
bool has_cursor = c->term.cursor.linear == linear_cursor - c->term.grid->offset;
|
||||
//bool has_cursor = false;
|
||||
|
||||
int x = col * c->term.cell_width;
|
||||
int y = row * c->term.cell_height;
|
||||
|
|
@ -160,15 +178,19 @@ grid_render_update(struct context *c, struct buffer *buf, const struct damage *d
|
|||
|
||||
wl_surface_damage_buffer(
|
||||
c->wl.surface,
|
||||
0, (dmg->range.start / cols) * c->term.cell_height,
|
||||
0, ((dmg->range.start - c->term.grid->offset) / cols) * c->term.cell_height,
|
||||
buf->width, (dmg->range.length + cols - 1) / cols * c->term.cell_height);
|
||||
}
|
||||
|
||||
static void
|
||||
grid_render_erase(struct context *c, struct buffer *buf, const struct damage *dmg)
|
||||
{
|
||||
LOG_DBG("damage: ERASE: %d -> %d",
|
||||
dmg->range.start, dmg->range.start + dmg->range.length);
|
||||
LOG_DBG("damage: ERASE: %d -> %d (offset = %d)",
|
||||
(dmg->range.start - c->term.grid->offset) % c->term.grid->size,
|
||||
(dmg->range.start - c->term.grid->offset) % c->term.grid->size + dmg->range.length,
|
||||
c->term.grid->offset);
|
||||
|
||||
assert(dmg->range.start >= c->term.grid->offset);
|
||||
|
||||
cairo_set_source_rgba(
|
||||
buf->cairo, default_background.r, default_background.g,
|
||||
|
|
@ -176,7 +198,7 @@ grid_render_erase(struct context *c, struct buffer *buf, const struct damage *dm
|
|||
|
||||
const int cols = c->term.cols;
|
||||
|
||||
int start = dmg->range.start;
|
||||
int start = (dmg->range.start - c->term.grid->offset) % c->term.grid->size;
|
||||
int left = dmg->range.length;
|
||||
|
||||
int row = start / cols;
|
||||
|
|
@ -238,17 +260,21 @@ grid_render_erase(struct context *c, struct buffer *buf, const struct damage *dm
|
|||
cairo_fill(buf->cairo);
|
||||
wl_surface_damage_buffer(c->wl.surface, x, y, width, height);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Redraw cursor, if it's inside the erased range */
|
||||
if (c->term.cursor.linear >= dmg->range.start &&
|
||||
c->term.cursor.linear < dmg->range.start + dmg->range.length)
|
||||
if (c->term.grid->offset + c->term.cursor.linear >= dmg->range.start &&
|
||||
c->term.grid->offset + c->term.cursor.linear < dmg->range.start + dmg->range.length)
|
||||
{
|
||||
grid_render_update(
|
||||
c, buf,
|
||||
&(struct damage){
|
||||
.type = DAMAGE_UPDATE,
|
||||
.range = {.start = c->term.cursor.linear, .length = 1}});
|
||||
.range = {
|
||||
.start = (c->term.grid->offset + c->term.cursor.linear) % c->term.grid->size,
|
||||
.length = 1}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -284,7 +310,7 @@ grid_render_scroll(struct context *c, struct buffer *buf,
|
|||
struct damage erase = {
|
||||
.type = DAMAGE_ERASE,
|
||||
.range = {
|
||||
.start = max(dmg->scroll.region.end - dmg->scroll.lines,
|
||||
.start = c->term.grid->offset + max(dmg->scroll.region.end - dmg->scroll.lines,
|
||||
dmg->scroll.region.start) * cols,
|
||||
.length = min(dmg->scroll.region.end - dmg->scroll.region.start,
|
||||
dmg->scroll.lines) * cols,
|
||||
|
|
@ -383,6 +409,8 @@ grid_render(struct context *c)
|
|||
tll_remove(c->term.grid->damage, it);
|
||||
}
|
||||
|
||||
c->term.grid->offset %= c->term.grid->size;
|
||||
|
||||
//cairo_surface_flush(buf->cairo_surface);
|
||||
wl_surface_attach(c->wl.surface, buf->wl_buf, 0, 0);
|
||||
|
||||
|
|
@ -450,8 +478,8 @@ resize(struct context *c, int width, int height)
|
|||
|
||||
/* Update environment variables */
|
||||
char cols_s[12], rows_s[12];
|
||||
sprintf(cols_s, "%u", c->term.cols);
|
||||
sprintf(rows_s, "%u", c->term.rows);
|
||||
sprintf(cols_s, "%d", c->term.cols);
|
||||
sprintf(rows_s, "%d", c->term.rows);
|
||||
setenv("COLUMNS", cols_s, 1);
|
||||
setenv("LINES", rows_s, 1);
|
||||
|
||||
|
|
|
|||
120
terminal.c
120
terminal.c
|
|
@ -6,6 +6,7 @@
|
|||
#define LOG_MODULE "terminal"
|
||||
#define LOG_ENABLE_DBG 1
|
||||
#include "log.h"
|
||||
#include "grid.h"
|
||||
|
||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
|
@ -37,10 +38,6 @@ damage_merge_range(struct terminal *term, const struct damage *dmg)
|
|||
old->range.start = new_start;
|
||||
old->range.length = new_end - new_start;
|
||||
|
||||
assert(old->range.start >= 0);
|
||||
assert(old->range.start < term->rows * term->cols);
|
||||
assert(old->range.length >= 0);
|
||||
assert(old->range.start + old->range.length <= term->rows * term->cols);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -53,14 +50,8 @@ term_damage_update_or_erase(struct terminal *term, enum damage_type damage_type,
|
|||
{
|
||||
struct damage dmg = {
|
||||
.type = damage_type,
|
||||
.range = {.start = start, .length = length},
|
||||
.range = {.start = term->grid->offset + start, .length = length},
|
||||
};
|
||||
|
||||
assert(dmg.range.start >= 0);
|
||||
assert(dmg.range.start < term->rows * term->cols);
|
||||
assert(dmg.range.length >= 0);
|
||||
assert(dmg.range.start + dmg.range.length <= term->rows * term->cols);
|
||||
|
||||
if (damage_merge_range(term, &dmg))
|
||||
return;
|
||||
|
||||
|
|
@ -70,12 +61,14 @@ term_damage_update_or_erase(struct terminal *term, enum damage_type damage_type,
|
|||
void
|
||||
term_damage_update(struct terminal *term, int start, int length)
|
||||
{
|
||||
assert(start + length <= term->rows * term->cols);
|
||||
term_damage_update_or_erase(term, DAMAGE_UPDATE, start, length);
|
||||
}
|
||||
|
||||
void
|
||||
term_damage_erase(struct terminal *term, int start, int length)
|
||||
{
|
||||
assert(start + length <= term->rows * term->cols);
|
||||
term_damage_update_or_erase(term, DAMAGE_ERASE, start, length);
|
||||
}
|
||||
|
||||
|
|
@ -87,82 +80,30 @@ term_damage_all(struct terminal *term)
|
|||
term_damage_update(term, 0, term->rows * term->cols);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
damage_adjust_after_scroll(struct terminal *term, enum damage_type damage_type,
|
||||
struct scroll_region region, int lines)
|
||||
{
|
||||
const int adjustment
|
||||
= lines * term->cols * (damage_type == DAMAGE_SCROLL_REVERSE ? -1 : 1);
|
||||
|
||||
const int scroll_start = region.start * term->cols;
|
||||
const int scroll_end = region.end * term->cols;
|
||||
|
||||
tll_foreach(term->grid->damage, it) {
|
||||
int start = it->item.range.start;
|
||||
int length = it->item.range.length;
|
||||
int end = start + length;
|
||||
|
||||
if (start < scroll_start && end > scroll_start) {
|
||||
/* Start outside, end either inside or on the other side */
|
||||
struct damage outside = {
|
||||
.type = it->item.type,
|
||||
.range = {.start = start, .length = scroll_start - start},
|
||||
};
|
||||
|
||||
tll_push_back(term->grid->damage, outside);
|
||||
start = scroll_start;
|
||||
length = end - start;
|
||||
|
||||
}
|
||||
|
||||
if (start < scroll_end && end > scroll_end) {
|
||||
/* End outside, start either inside or on the other side */
|
||||
struct damage outside = {
|
||||
.type = it->item.type,
|
||||
.range = {.start = scroll_end, .length = length - scroll_end},
|
||||
};
|
||||
|
||||
tll_push_back(term->grid->damage, outside);
|
||||
end = scroll_end;
|
||||
length = end - start;
|
||||
}
|
||||
|
||||
if (start >= scroll_start && end <= scroll_end) {
|
||||
/* Completely inside scroll region */
|
||||
start -= adjustment;
|
||||
it->item.range.start = start;
|
||||
|
||||
if (start < scroll_start) {
|
||||
/* Scrolled up outside scroll region */
|
||||
int new_length = length - (scroll_start - start);
|
||||
assert(new_length < length);
|
||||
|
||||
if (new_length <= 0)
|
||||
tll_remove(term->grid->damage, it);
|
||||
else {
|
||||
it->item.range.start = scroll_start;
|
||||
it->item.range.length = new_length;
|
||||
}
|
||||
}
|
||||
|
||||
if (start + length > scroll_end) {
|
||||
/* Scrolled down outside scroll region */
|
||||
if (start >= scroll_end)
|
||||
tll_remove(term->grid->damage, it);
|
||||
else {
|
||||
it->item.range.start = start;
|
||||
it->item.range.length = scroll_end - start;
|
||||
}
|
||||
if (it->item.range.start < term->grid->offset) {
|
||||
int end = it->item.range.start + it->item.range.length;
|
||||
if (end >= term->grid->offset) {
|
||||
it->item.range.start = term->grid->offset;
|
||||
it->item.range.length = end - it->item.range.start;
|
||||
} else {
|
||||
tll_remove(term->grid->damage, it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
term_damage_scroll(struct terminal *term, enum damage_type damage_type,
|
||||
struct scroll_region region, int lines)
|
||||
{
|
||||
damage_adjust_after_scroll(term, damage_type, region, lines);
|
||||
//damage_adjust_after_scroll(term, damage_type, region, lines);
|
||||
|
||||
if (tll_length(term->grid->scroll_damage) > 0) {
|
||||
struct damage *dmg = &tll_back(term->grid->scroll_damage);
|
||||
|
|
@ -185,8 +126,11 @@ term_damage_scroll(struct terminal *term, enum damage_type damage_type,
|
|||
void
|
||||
term_erase(struct terminal *term, int start, int end)
|
||||
{
|
||||
LOG_DBG("erase: %d-%d", start, end);
|
||||
assert(end >= start);
|
||||
memset(&term->grid->cells[start], 0, (end - start) * sizeof(term->grid->cells[0]));
|
||||
assert(end <= term->rows * term->cols);
|
||||
|
||||
grid_memset(term->grid, start, 0, end - start);
|
||||
term_damage_erase(term, start, end - start);
|
||||
}
|
||||
|
||||
|
|
@ -199,13 +143,10 @@ term_cursor_linear(const struct terminal *term, int row, int col)
|
|||
void
|
||||
term_cursor_to(struct terminal *term, int row, int col)
|
||||
{
|
||||
assert(row >= 0);
|
||||
assert(row < term->rows);
|
||||
assert(col >= 0);
|
||||
assert(col < term->cols);
|
||||
|
||||
int new_linear = row * term->cols + col;
|
||||
assert(new_linear >= 0);
|
||||
assert(new_linear < term->rows * term->cols);
|
||||
|
||||
term_damage_update(term, term->cursor.linear, 1);
|
||||
|
|
@ -248,11 +189,13 @@ term_cursor_down(struct terminal *term, int count)
|
|||
void
|
||||
term_scroll_partial(struct terminal *term, struct scroll_region region, int rows)
|
||||
{
|
||||
LOG_DBG("scroll: %d rows", rows);
|
||||
if (rows >= region.end - region.start) {
|
||||
assert(false && "untested");
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int cell_dst = (region.start + 0) * term->cols;
|
||||
int cell_src = (region.start + rows) * term->cols;
|
||||
int cell_count = (region.end - region.start - rows) * term->cols;
|
||||
|
|
@ -260,7 +203,7 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows
|
|||
LOG_DBG("moving %d lines from row %d to row %d", cell_count / term->cols,
|
||||
cell_src / term->cols, cell_dst / term->cols);
|
||||
|
||||
const size_t bytes = cell_count * sizeof(term->grid->cells[0]);
|
||||
const int bytes = cell_count * sizeof(term->grid->cells[0]);
|
||||
memmove(
|
||||
&term->grid->cells[cell_dst], &term->grid->cells[cell_src],
|
||||
bytes);
|
||||
|
|
@ -269,6 +212,15 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows
|
|||
rows * term->cols * sizeof(term->grid->cells[0]));
|
||||
|
||||
term_damage_scroll(term, DAMAGE_SCROLL, region, rows);
|
||||
#else
|
||||
/* TODO */
|
||||
assert(region.start == 0 && region.end == term->rows);
|
||||
assert(rows < term->rows);
|
||||
|
||||
term->grid->offset += rows * term->cols;
|
||||
grid_memset(term->grid, (region.end - rows) * term->cols, 0, rows * term->cols);
|
||||
term_damage_scroll(term, DAMAGE_SCROLL, region, rows);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -286,6 +238,7 @@ term_scroll_reverse_partial(struct terminal *term,
|
|||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int cell_dst = (region.start + rows) * term->cols;
|
||||
int cell_src = (region.start + 0) * term->cols;
|
||||
int cell_count = (region.end - region.start - rows) * term->cols;
|
||||
|
|
@ -293,7 +246,7 @@ term_scroll_reverse_partial(struct terminal *term,
|
|||
LOG_DBG("moving %d lines from row %d to row %d", cell_count / term->cols,
|
||||
cell_src / term->cols, cell_dst / term->cols);
|
||||
|
||||
const size_t bytes = cell_count * sizeof(term->grid->cells[0]);
|
||||
const int bytes = cell_count * sizeof(term->grid->cells[0]);
|
||||
memmove(
|
||||
&term->grid->cells[cell_dst], &term->grid->cells[cell_src],
|
||||
bytes);
|
||||
|
|
@ -302,6 +255,15 @@ term_scroll_reverse_partial(struct terminal *term,
|
|||
rows * term->cols * sizeof(term->grid->cells[0]));
|
||||
|
||||
term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows);
|
||||
#else
|
||||
/* TODO */
|
||||
assert(false);
|
||||
assert(region.start == 0 && region.end == 0);
|
||||
assert(rows < term->rows);
|
||||
|
||||
term->grid->offset -= rows * term->cols;
|
||||
term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
16
terminal.h
16
terminal.h
|
|
@ -62,8 +62,8 @@ struct damage {
|
|||
};
|
||||
|
||||
struct grid {
|
||||
size_t size;
|
||||
size_t offset;
|
||||
int size;
|
||||
int offset;
|
||||
|
||||
struct cell *cells;
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ struct grid {
|
|||
|
||||
struct vt_subparams {
|
||||
unsigned value[16];
|
||||
size_t idx;
|
||||
int idx;
|
||||
};
|
||||
|
||||
struct vt_param {
|
||||
|
|
@ -85,20 +85,20 @@ struct vt {
|
|||
int state; /* enum state */
|
||||
struct {
|
||||
struct vt_param v[16];
|
||||
size_t idx;
|
||||
int idx;
|
||||
} params;
|
||||
struct {
|
||||
uint8_t data[2];
|
||||
size_t idx;
|
||||
int idx;
|
||||
} intermediates;
|
||||
struct {
|
||||
uint8_t data[1024];
|
||||
size_t idx;
|
||||
int idx;
|
||||
} osc;
|
||||
struct {
|
||||
uint8_t data[4];
|
||||
size_t idx;
|
||||
size_t left;
|
||||
int idx;
|
||||
int left;
|
||||
} utf8;
|
||||
struct attributes attrs;
|
||||
bool dim;
|
||||
|
|
|
|||
6
vt.c
6
vt.c
|
|
@ -678,7 +678,11 @@ action(struct terminal *term, enum action action, uint8_t c)
|
|||
term_cursor_to(term, term->cursor.row + 1, 0);
|
||||
}
|
||||
|
||||
struct cell *cell = &term->grid->cells[term->cursor.linear];
|
||||
size_t cell_count = 1;
|
||||
struct cell *cell = grid_get_range(
|
||||
term->grid, term->cursor.linear, &cell_count);
|
||||
assert(cell_count == 1);
|
||||
|
||||
term_damage_update(term, term->cursor.linear, 1);
|
||||
|
||||
if (term->vt.utf8.idx > 0) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue