summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-06-10 21:24:12 +0200
committerBram Moolenaar <Bram@vim.org>2019-06-10 21:24:12 +0200
commit4c063a0dab57be7bd7aad4b8434feff3db5f1057 (patch)
treee73db7e8dfa79610e7c4b1a4a846688cf0f1b04f
parent640d4f0c97e686211dc4474b46a83e4435d883c0 (diff)
downloadvim-git-4c063a0dab57be7bd7aad4b8434feff3db5f1057.tar.gz
patch 8.1.1517: when a popup changes all windows are redrawnv8.1.1517
Problem: When a popup changes all windows are redrawn. Solution: Only update the lines that were affected. Add a file for profiling popup windows efficiency.
-rw-r--r--Filelist1
-rw-r--r--src/globals.h1
-rw-r--r--src/popupwin.c3
-rw-r--r--src/proto/screen.pro1
-rw-r--r--src/screen.c116
-rw-r--r--src/testdir/popupbounce.vim80
-rw-r--r--src/ui.c10
-rw-r--r--src/version.c2
8 files changed, 178 insertions, 36 deletions
diff --git a/Filelist b/Filelist
index 7bf4fd675..99e10048f 100644
--- a/Filelist
+++ b/Filelist
@@ -152,6 +152,7 @@ SRC_ALL = \
src/testdir/if_ver*.vim \
src/testdir/color_ramp.vim \
src/testdir/silent.wav \
+ src/testdir/popupbounce.vim \
src/proto.h \
src/protodef.h \
src/proto/arabic.pro \
diff --git a/src/globals.h b/src/globals.h
index 06091f97b..3e6154573 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -73,6 +73,7 @@ EXTERN short *TabPageIdxs INIT(= NULL);
#ifdef FEAT_TEXT_PROP
// Array with size Rows x Columns containing zindex of popups.
EXTERN short *popup_mask INIT(= NULL);
+EXTERN short *popup_mask_next INIT(= NULL);
// Flag set to TRUE when popup_mask needs to be updated.
EXTERN int popup_mask_refresh INIT(= TRUE);
diff --git a/src/popupwin.c b/src/popupwin.c
index c5123697d..3781c6fe2 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -571,8 +571,7 @@ popup_adjust_position(win_T *wp)
|| org_width != wp->w_width
|| org_height != wp->w_height)
{
- // TODO: redraw only windows that were below the popup.
- redraw_all_later(NOT_VALID);
+ redraw_all_later(VALID);
popup_mask_refresh = TRUE;
}
}
diff --git a/src/proto/screen.pro b/src/proto/screen.pro
index 8c2e0083b..ab73e0ba9 100644
--- a/src/proto/screen.pro
+++ b/src/proto/screen.pro
@@ -16,7 +16,6 @@ int update_screen(int type_arg);
int conceal_cursor_line(win_T *wp);
void conceal_check_cursor_line(void);
void update_debug_sign(buf_T *buf, linenr_T lnum);
-int may_update_popup_mask(int type_arg);
void updateWindow(win_T *wp);
int screen_get_current_line_off(void);
void screen_line(int row, int coloff, int endcol, int clear_width, int flags);
diff --git a/src/screen.c b/src/screen.c
index fae9fe7eb..1ffc729df 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -122,6 +122,7 @@ static int redrawing_for_callback = 0;
static schar_T *current_ScreenLine;
#ifdef FEAT_TEXT_PROP
+static void may_update_popup_mask(int type);
static void update_popups(void);
#endif
static void win_update(win_T *wp);
@@ -612,8 +613,9 @@ update_screen(int type_arg)
}
#ifdef FEAT_TEXT_PROP
- // Update popup_mask if needed.
- type = may_update_popup_mask(type);
+ // Update popup_mask if needed. This may set w_redraw_top and w_redraw_bot
+ // in some windows.
+ may_update_popup_mask(type);
#endif
updating_screen = TRUE;
@@ -1014,17 +1016,19 @@ get_wcr_attr(win_T *wp)
}
#ifdef FEAT_TEXT_PROP
+
/*
* Update "popup_mask" if needed.
* Also recomputes the popup size and positions.
* Also updates "popup_visible".
- * If more redrawing is needed than "type_arg" a higher value is returned.
+ * Also marks window lines for redrawing.
*/
- int
-may_update_popup_mask(int type_arg)
+ static void
+may_update_popup_mask(int type)
{
- int type = type_arg;
win_T *wp;
+ short *mask;
+ int line, col;
if (popup_mask_tab != curtab)
popup_mask_refresh = TRUE;
@@ -1038,14 +1042,22 @@ may_update_popup_mask(int type_arg)
if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
popup_mask_refresh = TRUE;
if (!popup_mask_refresh)
- return type;
+ return;
}
+ // Need to update the mask, something has changed.
popup_mask_refresh = FALSE;
popup_mask_tab = curtab;
-
popup_visible = FALSE;
- vim_memset(popup_mask, 0, screen_Rows * screen_Columns * sizeof(short));
+
+ // If redrawing everything, just update "popup_mask".
+ // If redrawing only what is needed, update "popup_mask_next" and then
+ // compare with "popup_mask" to see what changed.
+ if (type >= SOME_VALID)
+ mask = popup_mask;
+ else
+ mask = popup_mask_next;
+ vim_memset(mask, 0, screen_Rows * screen_Columns * sizeof(short));
// Find the window with the lowest zindex that hasn't been handled yet,
// so that the window with a higher zindex overwrites the value in
@@ -1053,10 +1065,7 @@ may_update_popup_mask(int type_arg)
popup_reset_handled();
while ((wp = find_next_popup(TRUE)) != NULL)
{
- int top_off, bot_off;
- int left_off, right_off;
- short *p;
- int line, col;
+ int height_extra, width_extra;
popup_visible = TRUE;
@@ -1064,30 +1073,71 @@ may_update_popup_mask(int type_arg)
if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
popup_adjust_position(wp);
- // the position and size are for the inside, add the padding and
+ // the width and height are for the inside, add the padding and
// border
- top_off = wp->w_popup_padding[0] + wp->w_popup_border[0];
- bot_off = wp->w_popup_padding[2] + wp->w_popup_border[2];
- left_off = wp->w_popup_padding[3] + wp->w_popup_border[3];
- right_off = wp->w_popup_padding[1] + wp->w_popup_border[1];
+ height_extra = wp->w_popup_padding[0] + wp->w_popup_border[0]
+ + wp->w_popup_padding[2] + wp->w_popup_border[2];
+ width_extra = wp->w_popup_padding[3] + wp->w_popup_border[3]
+ + wp->w_popup_padding[1] + wp->w_popup_border[1];
- for (line = wp->w_winrow + top_off;
- line < wp->w_winrow + wp->w_height + bot_off
+ for (line = wp->w_winrow;
+ line < wp->w_winrow + wp->w_height + height_extra
&& line < screen_Rows; ++line)
- for (col = wp->w_wincol + left_off;
- col < wp->w_wincol + wp->w_width + right_off
+ for (col = wp->w_wincol;
+ col < wp->w_wincol + wp->w_width + width_extra
&& col < screen_Columns; ++col)
+ mask[line * screen_Columns + col] = wp->w_zindex;
+ }
+
+ // Only check which lines are to be updated if not already
+ // updating all lines.
+ if (mask == popup_mask_next)
+ for (line = 0; line < screen_Rows; ++line)
+ {
+ int col_done = 0;
+
+ for (col = 0; col < screen_Columns; ++col)
{
- p = popup_mask + line * screen_Columns + col;
- if (*p != wp->w_zindex)
+ int off = line * screen_Columns + col;
+
+ if (popup_mask[off] != popup_mask_next[off])
{
- *p = wp->w_zindex;
- type = NOT_VALID;
+ popup_mask[off] = popup_mask_next[off];
+
+ // The screen position "line" / "col" needs to be redrawn.
+ // Figure out what window that is and update w_redraw_top
+ // and w_redr_bot. Only needs to be done for each window
+ // line.
+ if (col >= col_done)
+ {
+ linenr_T lnum;
+ int line_cp = line;
+ int col_cp = col;
+
+ // find the window where the row is in
+ wp = mouse_find_win(&line_cp, &col_cp);
+ if (wp != NULL)
+ {
+ if (line_cp >= wp->w_height)
+ // In (or below) status line
+ wp->w_redr_status = TRUE;
+ // compute the position in the buffer line from the
+ // position on the screen
+ else if (mouse_comp_pos(wp, &line_cp, &col_cp,
+ &lnum))
+ // past bottom
+ wp->w_redr_status = TRUE;
+ else
+ redrawWinline(wp, lnum);
+
+ // This line is going to be redrawn, no need to
+ // check until the right side of the window.
+ col_done = wp->w_wincol + wp->w_width - 1;
+ }
+ }
}
}
- }
-
- return type;
+ }
}
/*
@@ -9112,6 +9162,7 @@ screenalloc(int doclear)
short *new_TabPageIdxs;
#ifdef FEAT_TEXT_PROP
short *new_popup_mask;
+ short *new_popup_mask_next;
#endif
tabpage_T *tp;
static int entered = FALSE; /* avoid recursiveness */
@@ -9196,6 +9247,7 @@ retry:
new_TabPageIdxs = LALLOC_MULT(short, Columns);
#ifdef FEAT_TEXT_PROP
new_popup_mask = LALLOC_MULT(short, Rows * Columns);
+ new_popup_mask_next = LALLOC_MULT(short, Rows * Columns);
#endif
FOR_ALL_TAB_WINDOWS(tp, wp)
@@ -9241,6 +9293,7 @@ give_up:
|| new_TabPageIdxs == NULL
#ifdef FEAT_TEXT_PROP
|| new_popup_mask == NULL
+ || new_popup_mask_next == NULL
#endif
|| outofmem)
{
@@ -9264,6 +9317,7 @@ give_up:
VIM_CLEAR(new_TabPageIdxs);
#ifdef FEAT_TEXT_PROP
VIM_CLEAR(new_popup_mask);
+ VIM_CLEAR(new_popup_mask_next);
#endif
}
else
@@ -9353,6 +9407,7 @@ give_up:
TabPageIdxs = new_TabPageIdxs;
#ifdef FEAT_TEXT_PROP
popup_mask = new_popup_mask;
+ popup_mask_next = new_popup_mask_next;
vim_memset(popup_mask, 0, Rows * Columns * sizeof(short));
popup_mask_refresh = TRUE;
#endif
@@ -9421,6 +9476,7 @@ free_screenlines(void)
VIM_CLEAR(TabPageIdxs);
#ifdef FEAT_TEXT_PROP
VIM_CLEAR(popup_mask);
+ VIM_CLEAR(popup_mask_next);
#endif
}
@@ -10027,7 +10083,7 @@ win_do_lines(
}
#ifdef FEAT_TEXT_PROP
- // this doesn't work when tere are popups visible
+ // this doesn't work when there are popups visible
if (popup_visible)
return FAIL;
#endif
diff --git a/src/testdir/popupbounce.vim b/src/testdir/popupbounce.vim
new file mode 100644
index 000000000..2d1345bfd
--- /dev/null
+++ b/src/testdir/popupbounce.vim
@@ -0,0 +1,80 @@
+" Use this script to measure the redrawing performance when a popup is being
+" displayed. Usage with gcc:
+" cd src
+" # Edit Makefile to uncomment PROFILE_CFLAGS and PROFILE_LIBS
+" make reconfig
+" ./vim --clean -S testdir/popupbounce.vim main.c
+" gprof vim gmon.out | vim -
+
+" using line contination
+set nocp
+
+" don't switch screens when quitting, so we can read the frames/sec
+set t_te=
+
+let winid = popup_create(['line1', 'line2', 'line3', 'line4'], {
+ \ 'line' : 1,
+ \ 'col' : 1,
+ \ 'zindex' : 101,
+ \ })
+redraw
+
+let start = reltime()
+let framecount = 0
+
+let line = 1.0
+let col = 1
+let downwards = 1
+let col_inc = 1
+let initial_speed = 0.2
+let speed = initial_speed
+let accel = 1.1
+let time = 0.1
+
+let countdown = 0
+
+while 1
+ if downwards
+ let speed += time * accel
+ let line += speed
+ else
+ let speed -= time * accel
+ let line -= speed
+ endif
+
+ if line + 3 >= &lines
+ let downwards = 0
+ let speed = speed * 0.8
+ let line = &lines - 3
+ endif
+ if !downwards && speed < 1.0
+ let downwards = 1
+ let speed = initial_speed
+ if line + 4 > &lines && countdown == 0
+ let countdown = 50
+ endif
+ endif
+
+ let col += col_inc
+ if col + 4 >= &columns
+ let col_inc = -1
+ elseif col <= 1
+ let col_inc = 1
+ endif
+
+ call popup_move(winid, {'line': float2nr(line), 'col': col})
+ redraw
+ let framecount += 1
+ if countdown > 0
+ let countdown -= 1
+ if countdown == 0
+ break
+ endif
+ endif
+
+endwhile
+
+let elapsed = reltimefloat(reltime(start))
+echomsg framecount .. ' frames in ' .. string(elapsed) .. ' seconds, ' .. string(framecount / elapsed) .. ' frames/sec'
+
+qa
diff --git a/src/ui.c b/src/ui.c
index ed0e50abe..4a684d236 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -3242,15 +3242,19 @@ retnomove:
|| curwin->w_cursor.col != old_cursor.col)
count |= CURSOR_MOVED; /* Cursor has moved */
-#ifdef FEAT_FOLDING
+# ifdef FEAT_FOLDING
if (mouse_char == '+')
count |= MOUSE_FOLD_OPEN;
else if (mouse_char != ' ')
count |= MOUSE_FOLD_CLOSE;
-#endif
+# endif
return count;
}
+#endif
+
+// Functions also used for popup windows.
+#if defined(FEAT_MOUSE) || defined(FEAT_TEXT_PROP) || defined(PROTO)
/*
* Compute the position in the buffer line from the posn on the screen in
@@ -3347,7 +3351,7 @@ mouse_comp_pos(
* Returns NULL when something is wrong.
*/
win_T *
-mouse_find_win(int *rowp, int *colp UNUSED)
+mouse_find_win(int *rowp, int *colp)
{
frame_T *fp;
win_T *wp;
diff --git a/src/version.c b/src/version.c
index c4c8e3fc1..7a6629588 100644
--- a/src/version.c
+++ b/src/version.c
@@ -778,6 +778,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1517,
+/**/
1516,
/**/
1515,