From 0de3701984ff3b09a804d8369dafc3cd5baefdcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 23 Mar 2020 20:45:27 +0100 Subject: [PATCH] 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. --- render.c | 63 ++++++++++---------------------------------------------- shm.c | 49 +++++++++++++++++++++++++++++++++++++------ shm.h | 4 +++- 3 files changed, 57 insertions(+), 59 deletions(-) diff --git a/render.c b/render.c index 89b8fd0e..2eab275e 100644 --- a/render.c +++ b/render.c @@ -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, diff --git a/shm.c b/shm.c index 59dcb2ac..d05210a2 100644 --- a/shm.c +++ b/shm.c @@ -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 diff --git a/shm.h b/shm.h index 6801ed93..6637182c 100644 --- a/shm.h +++ b/shm.h @@ -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);