mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-20 01:40:14 -05:00
shm: shm_scroll(): initial implementation of reverse scrolling
Implemented by truncating the file size and moving the offset backwards. This means we can only reverse scroll when we've previously scrolled forward. TODO: figure out if we can somehow do fast reverse scrolling even though offset is 0 (or well, less than required for scrolling).
This commit is contained in:
parent
0de3701984
commit
759fd572e9
2 changed files with 143 additions and 28 deletions
71
render.c
71
render.c
|
|
@ -602,14 +602,6 @@ grid_render_scroll(struct terminal *term, struct buffer *buf,
|
|||
term->wl->shm, buf, dmg->scroll.lines * term->cell_height,
|
||||
term->margins.top, dmg->scroll.region.start * term->cell_height,
|
||||
term->margins.bottom, (term->rows - dmg->scroll.region.end) * term->cell_height);
|
||||
|
||||
if (!did_shm_scroll)
|
||||
LOG_DBG("fast scroll failed");
|
||||
} else {
|
||||
LOG_DBG(
|
||||
"skipping SHM scroll "
|
||||
"(region.start=%d, bottom-region-lines=%d, term-lines=%d)",
|
||||
dmb->scroll.region.start, scroll_region_lines, term->rows);
|
||||
}
|
||||
|
||||
if (did_shm_scroll) {
|
||||
|
|
@ -647,26 +639,65 @@ static void
|
|||
grid_render_scroll_reverse(struct terminal *term, struct buffer *buf,
|
||||
const struct damage *dmg)
|
||||
{
|
||||
int src_y = term->margins.top + (dmg->scroll.region.start + 0) * term->cell_height;
|
||||
int dst_y = term->margins.top + (dmg->scroll.region.start + dmg->scroll.lines) * term->cell_height;
|
||||
int height = (dmg->scroll.region.end - dmg->scroll.region.start - dmg->scroll.lines) * term->cell_height;
|
||||
|
||||
LOG_DBG("damage: SCROLL REVERSE: %d-%d by %d lines (dst-y: %d, src-y: %d, "
|
||||
"height: %d, stride: %d, mmap-size: %zu)",
|
||||
dmg->scroll.region.start, dmg->scroll.region.end,
|
||||
dmg->scroll.lines,
|
||||
dst_y, src_y, height, buf->stride,
|
||||
buf->size);
|
||||
LOG_DBG(
|
||||
"damage: SCROLL REVERSE: %d-%d by %d lines"m
|
||||
dmg->scroll.region.start, dmg->scroll.region.end, dmg->scroll.lines);
|
||||
|
||||
if (height > 0) {
|
||||
if (height <= 0)
|
||||
return;
|
||||
|
||||
#if TIME_SCROLL_DAMAGE
|
||||
struct timeval start_time;
|
||||
gettimeofday(&start_time, NULL);
|
||||
#endif
|
||||
|
||||
int src_y = term->margins.top + (dmg->scroll.region.start + 0) * term->cell_height;
|
||||
int dst_y = term->margins.top + (dmg->scroll.region.start + dmg->scroll.lines) * term->cell_height;
|
||||
|
||||
bool try_shm_scroll =
|
||||
shm_can_scroll() && (dmg->scroll.lines +
|
||||
dmg->scroll.region.start +
|
||||
(term->rows - dmg->scroll.region.end)) < term->rows / 2;
|
||||
|
||||
bool did_shm_scroll = false;
|
||||
|
||||
if (try_shm_scroll) {
|
||||
did_shm_scroll = shm_scroll(
|
||||
term->wl->shm, buf, -dmg->scroll.lines * term->cell_height,
|
||||
term->margins.top, dmg->scroll.region.start * term->cell_height,
|
||||
term->margins.bottom, (term->rows - dmg->scroll.region.end) * term->cell_height);
|
||||
}
|
||||
|
||||
if (did_shm_scroll) {
|
||||
/* Restore margins */
|
||||
render_margin(
|
||||
term, buf, dmg->scroll.region.start, dmg->scroll.region.start + dmg->scroll.lines,
|
||||
true, true);
|
||||
} else {
|
||||
/* Fallback for when we either cannot do SHM scrolling, or it failed */
|
||||
uint8_t *raw = buf->mmapped;
|
||||
memmove(raw + dst_y * buf->stride,
|
||||
raw + src_y * buf->stride,
|
||||
height * buf->stride);
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->window->surface, term->margins.left, dst_y, term->width - term->margins.left - term->margins.right, height);
|
||||
}
|
||||
|
||||
#if TIME_SCROLL_DAMAGE
|
||||
struct timeval end_time;
|
||||
gettimeofday(&end_time, NULL);
|
||||
|
||||
struct timeval memmove_time;
|
||||
timersub(&end_time, &start_time, &memmove_time);
|
||||
LOG_INFO("scrolled REVERSE %dKB (%d lines) using %s in %lds %ldus",
|
||||
height * buf->stride / 1024, dmg->scroll.lines,
|
||||
did_shm_scroll ? "SHM" : try_shm_scroll ? "memmove (SHM failed)" : "memmove",
|
||||
memmove_time.tv_sec, memmove_time.tv_usec);
|
||||
#endif
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->window->surface, term->margins.left, dst_y,
|
||||
term->width - term->margins.left - term->margins.right, height);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
100
shm.c
100
shm.c
|
|
@ -64,8 +64,6 @@ instantiate_offset(struct wl_shm *shm, struct buffer *buf, size_t new_offset)
|
|||
assert(buf->wl_buf == NULL);
|
||||
assert(buf->pix == NULL);
|
||||
|
||||
assert(new_offset >= buf->offset);
|
||||
|
||||
static size_t page_size = 0;
|
||||
if (page_size == 0) {
|
||||
page_size = sysconf(_SC_PAGE_SIZE);
|
||||
|
|
@ -286,10 +284,10 @@ shm_can_scroll(void)
|
|||
return can_punch_hole;
|
||||
}
|
||||
|
||||
bool
|
||||
shm_scroll(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||
int top_margin, int top_keep_rows,
|
||||
int bottom_margin, int bottom_keep_rows)
|
||||
static bool
|
||||
shm_scroll_forward(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||
int top_margin, int top_keep_rows,
|
||||
int bottom_margin, int bottom_keep_rows)
|
||||
{
|
||||
assert(can_punch_hole);
|
||||
assert(buf->busy);
|
||||
|
|
@ -365,7 +363,6 @@ shm_scroll(struct wl_shm *shm, struct buffer *buf, int rows,
|
|||
LOG_INFO("PUNCH HOLE: %lds %ldus", tot.tv_sec, tot.tv_usec);
|
||||
#endif
|
||||
|
||||
|
||||
bool ret = instantiate_offset(shm, buf, new_offset);
|
||||
|
||||
if (ret && bottom_keep_rows > 0) {
|
||||
|
|
@ -387,7 +384,94 @@ shm_scroll(struct wl_shm *shm, struct buffer *buf, int rows,
|
|||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
static bool
|
||||
shm_scroll_reverse(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||
int top_margin, int top_keep_rows,
|
||||
int bottom_margin, int bottom_keep_rows)
|
||||
{
|
||||
assert(rows > 0);
|
||||
|
||||
size_t diff = rows * buf->stride;
|
||||
if (diff > buf->offset)
|
||||
return false;
|
||||
|
||||
const size_t new_offset = buf->offset - rows * buf->stride;
|
||||
assert(new_offset < buf->offset);
|
||||
|
||||
#if TIME_SCROLL
|
||||
struct timeval time0;
|
||||
gettimeofday(&time0, NULL);
|
||||
|
||||
struct timeval tot;
|
||||
struct timeval time1 = time0;
|
||||
#endif
|
||||
|
||||
if (bottom_keep_rows > 0) {
|
||||
/* Copy 'bottom' region to its new location */
|
||||
memmove(
|
||||
(uint8_t *)buf->mmapped + buf->size - (bottom_margin + rows + bottom_keep_rows) * buf->stride,
|
||||
(uint8_t *)buf->mmapped + buf->size - (bottom_margin + bottom_keep_rows) * buf->stride,
|
||||
bottom_keep_rows * buf->stride);
|
||||
|
||||
#if TIME_SCROLL
|
||||
gettimeofday(&time1, NULL);
|
||||
timersub(&time1, &time0, &tot);
|
||||
LOG_INFO("memmove (bottom region): %lds %ldus", tot.tv_sec, tot.tv_usec);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Destroy old objects (they point to the old offset) */
|
||||
pixman_image_unref(buf->pix);
|
||||
wl_buffer_destroy(buf->wl_buf);
|
||||
munmap(buf->real_mmapped, buf->mmap_size);
|
||||
|
||||
buf->pix = NULL;
|
||||
buf->wl_buf = NULL;
|
||||
buf->real_mmapped = buf->mmapped = NULL;
|
||||
|
||||
if (ftruncate(buf->fd, new_offset + buf->size) < 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
#if TIME_SCROLL
|
||||
struct timeval time2;
|
||||
gettimeofday(&time2, NULL);
|
||||
timersub(&time2, &time1, &tot);
|
||||
LOG_INFO("ftruncate: %lds %ldus", tot.tv_sec, tot.tv_usec);
|
||||
#endif
|
||||
|
||||
bool ret = instantiate_offset(shm, buf, new_offset);
|
||||
|
||||
if (ret && top_keep_rows > 0) {
|
||||
/* Copy current 'top' region to its new location */
|
||||
memmove(
|
||||
(uint8_t *)buf->mmapped + (top_margin + 0) * buf->stride,
|
||||
(uint8_t *)buf->mmapped + (top_margin + rows) * buf->stride,
|
||||
top_keep_rows * buf->stride);
|
||||
|
||||
#if TIME_SCROLL
|
||||
struct timeval time3;
|
||||
gettimeofday(&time3, NULL);
|
||||
timersub(&time3, &time2, &tot);
|
||||
LOG_INFO("memmove (top region): %lds %ldus", tot.tv_sec, tot.tv_usec);
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
shm_scroll(struct wl_shm *shm, struct buffer *buf, int rows,
|
||||
int top_margin, int top_keep_rows,
|
||||
int bottom_margin, int bottom_keep_rows)
|
||||
{
|
||||
assert(rows != 0);
|
||||
return rows > 0
|
||||
? shm_scroll_forward(shm, buf, rows, top_margin, top_keep_rows, bottom_margin, bottom_keep_rows)
|
||||
: shm_scroll_reverse(shm, buf, -rows, top_margin, top_keep_rows, bottom_margin, bottom_keep_rows);
|
||||
}
|
||||
|
||||
void
|
||||
shm_purge(struct wl_shm *shm, unsigned long cookie)
|
||||
{
|
||||
LOG_DBG("cookie=%lx: purging all buffers", cookie);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue