shm: scroll: move top/bottom region handling from renderer into shm

This allows us to restore the regions without copying the contents to
temporary memory.
This commit is contained in:
Daniel Eklöf 2020-03-23 20:45:27 +01:00
parent 00129b1935
commit 0de3701984
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
3 changed files with 57 additions and 59 deletions

View file

@ -551,7 +551,6 @@ grid_render_scroll(struct terminal *term, struct buffer *buf,
gettimeofday(&start_time, NULL);
#endif
uint8_t *raw = buf->mmapped;
int dst_y = term->margins.top + (dmg->scroll.region.start + 0) * term->cell_height;
int src_y = term->margins.top + (dmg->scroll.region.start + dmg->scroll.lines) * term->cell_height;
@ -563,12 +562,13 @@ grid_render_scroll(struct terminal *term, struct buffer *buf,
* memmove, while scrolling a *small* number of lines is faster
* with SHM scrolling.
*
* However, since we need to restore the bottom scrolling region
* when SHM scrolling, we also need to take this into account.
* However, since we need to restore the scrolling regions when
* SHM scrolling, we also need to take this into account.
*
* Finally, restoring the window margins is a *huge* performance
* hit when scrolling a large number of lines (in addition to the
* sloweness of SHM scrolling as method).
* Finally, we also have to restore the window margins, and this
* is a *huge* performance hit when scrolling a large number of
* lines (in addition to the sloweness of SHM scrolling as
* method).
*
* So, we need to figure out when to SHM scroll, and when to
* memmove.
@ -597,19 +597,11 @@ grid_render_scroll(struct terminal *term, struct buffer *buf,
//try_shm_scroll = false;
//try_shm_scroll = true;
/* TODO: this could easily use up all stack */
uint8_t top_region[dmg->scroll.region.start * term->cell_height * buf->stride];
if (try_shm_scroll) {
if (dmg->scroll.region.start > 0) {
/* Store a copy of the top region - we need to restore it after scrolling */
memcpy(top_region,
(uint8_t *)buf->mmapped + term->margins.top * buf->stride,
sizeof(top_region));
}
did_shm_scroll = shm_scroll(
term->wl->shm, buf, dmg->scroll.lines * term->cell_height);
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");
@ -620,47 +612,14 @@ grid_render_scroll(struct terminal *term, struct buffer *buf,
dmb->scroll.region.start, scroll_region_lines, term->rows);
}
/*
* When SHM scrolling succeeded, the scrolled in area is made up
* of newly allocated, zero-initialized memory. Thus we'll need to
* both copy the bottom scrolling region, and re-render the window
* margins.
*
* This is different from when we scroll with a simple memmove,
* since in that case, the scrolling region and margins are
* *copied*, and thus the original region+margin remains in place.
*/
if (did_shm_scroll) {
/* Mmap changed - update buffer pointer */
raw = buf->mmapped;
/* Restore top scrolling region */
memcpy(raw + term->margins.top * buf->stride, top_region, sizeof(top_region));
/* Restore bottom scrolling region */
if (dmg->scroll.region.end < term->rows) {
int src = dmg->scroll.region.end - dmg->scroll.lines;
int dst = dmg->scroll.region.end;
size_t amount = term->rows - dmg->scroll.region.end;
LOG_DBG("memmoving %zu lines of scroll region", amount);
assert(src >= 0);
memmove(
raw + (term->margins.top + dst * term->cell_height) * buf->stride,
raw + (term->margins.top + src * term->cell_height) * buf->stride,
amount * term->cell_height * buf->stride);
}
/* Restore margins */
render_margin(
term, buf, dmg->scroll.region.end - dmg->scroll.lines, term->rows,
true, true);
}
/* Fallback for when we either cannot do SHM scrolling, or it failed */
if (!did_shm_scroll) {
} 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,

49
shm.c
View file

@ -287,7 +287,9 @@ shm_can_scroll(void)
}
bool
shm_scroll(struct wl_shm *shm, struct buffer *buf, int rows)
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(can_punch_hole);
assert(buf->busy);
@ -323,9 +325,25 @@ shm_scroll(struct wl_shm *shm, struct buffer *buf, int rows)
struct timeval tot;
timersub(&time1, &time0, &tot);
LOG_INFO("fallocate: %lds %ldus", tot.tv_sec, tot.tv_usec);
LOG_INFO("ftruncate: %lds %ldus", tot.tv_sec, tot.tv_usec);
struct timeval time2 = time1;
#endif
if (top_keep_rows > 0) {
/* Copy current 'top' region to its new location */
memmove(
(uint8_t *)buf->mmapped + (top_margin + rows) * buf->stride,
(uint8_t *)buf->mmapped + (top_margin + 0) * buf->stride,
top_keep_rows * buf->stride);
#if TIME_SCROLL
gettimeofday(&time2, NULL);
timersub(&time2, &time1, &tot);
LOG_INFO("memmove (top 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);
@ -341,13 +359,32 @@ shm_scroll(struct wl_shm *shm, struct buffer *buf, int rows)
}
#if TIME_SCROLL
struct timeval time2;
gettimeofday(&time2, NULL);
timersub(&time2, &time1, &tot);
struct timeval time3;
gettimeofday(&time3, NULL);
timersub(&time3, &time2, &tot);
LOG_INFO("PUNCH HOLE: %lds %ldus", tot.tv_sec, tot.tv_usec);
#endif
return instantiate_offset(shm, buf, new_offset);
bool ret = instantiate_offset(shm, buf, new_offset);
if (ret && bottom_keep_rows > 0) {
/* Copy 'bottom' region to its new location */
memmove(
(uint8_t *)buf->mmapped + buf->size - (bottom_margin + bottom_keep_rows) * buf->stride,
(uint8_t *)buf->mmapped + buf->size - (bottom_margin + rows + bottom_keep_rows) * buf->stride,
bottom_keep_rows * buf->stride);
#if TIME_SCROLL
struct timeval time4;
gettimeofday(&time4, NULL);
timersub(&time4, &time3, &tot);
LOG_INFO("memmove (bottom region): %lds %ldus", tot.tv_sec, tot.tv_usec);
#endif
}
return ret;
}
void

4
shm.h
View file

@ -33,7 +33,9 @@ struct buffer *shm_get_buffer(
void shm_fini(void);
bool shm_can_scroll(void);
bool shm_scroll(struct wl_shm *shm, struct buffer *buf, int rows);
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);
void shm_purge(struct wl_shm *shm, unsigned long cookie);