Patch 8.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.
Files: src/screen.c, src/proto/screen.pro, src/ui.c, src/popupwin.c,
src/globals.h, src/testdir/popupbounce.vim, Filelist
*** ../vim-8.1.1516/src/screen.c 2019-06-09 18:04:09.839426999 +0200
--- src/screen.c 2019-06-10 21:21:09.932434241 +0200
***************
*** 122,127 ****
--- 122,128 ----
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,619 ****
}
#ifdef FEAT_TEXT_PROP
! // Update popup_mask if needed.
! type = may_update_popup_mask(type);
#endif
updating_screen = TRUE;
--- 613,621 ----
}
#ifdef FEAT_TEXT_PROP
! // 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,1030 ****
}
#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.
*/
! int
! may_update_popup_mask(int type_arg)
{
- int type = type_arg;
win_T *wp;
if (popup_mask_tab != curtab)
popup_mask_refresh = TRUE;
--- 1016,1034 ----
}
#ifdef FEAT_TEXT_PROP
+
/*
* Update "popup_mask" if needed.
* Also recomputes the popup size and positions.
* Also updates "popup_visible".
! * Also marks window lines for redrawing.
*/
! static void
! may_update_popup_mask(int type)
{
win_T *wp;
+ short *mask;
+ int line, col;
if (popup_mask_tab != curtab)
popup_mask_refresh = TRUE;
***************
*** 1038,1051 ****
if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
popup_mask_refresh = TRUE;
if (!popup_mask_refresh)
! return type;
}
popup_mask_refresh = FALSE;
popup_mask_tab = curtab;
-
popup_visible = FALSE;
! vim_memset(popup_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
--- 1042,1063 ----
if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
popup_mask_refresh = TRUE;
if (!popup_mask_refresh)
! return;
}
+ // Need to update the mask, something has changed.
popup_mask_refresh = FALSE;
popup_mask_tab = curtab;
popup_visible = FALSE;
!
! // 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,1062 ****
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;
popup_visible = TRUE;
--- 1065,1071 ----
popup_reset_handled();
while ((wp = find_next_popup(TRUE)) != NULL)
{
! int height_extra, width_extra;
popup_visible = TRUE;
***************
*** 1064,1093 ****
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
// 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];
! for (line = wp->w_winrow + top_off;
! line < wp->w_winrow + wp->w_height + bot_off
&& line < screen_Rows; ++line)
! for (col = wp->w_wincol + left_off;
! col < wp->w_wincol + wp->w_width + right_off
&& col < screen_Columns; ++col)
{
! p = popup_mask + line * screen_Columns + col;
! if (*p != wp->w_zindex)
{
! *p = wp->w_zindex;
! type = NOT_VALID;
}
}
! }
!
! return type;
}
/*
--- 1073,1143 ----
if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
popup_adjust_position(wp);
! // the width and height are for the inside, add the padding and
// border
! 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;
! line < wp->w_winrow + wp->w_height + height_extra
&& line < screen_Rows; ++line)
! 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)
{
! int off = line * screen_Columns + col;
!
! if (popup_mask[off] != popup_mask_next[off])
{
! 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;
! }
! }
}
}
! }
}
/*
***************
*** 9112,9117 ****
--- 9162,9168 ----
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,9201 ****
--- 9247,9253 ----
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,9246 ****
--- 9293,9299 ----
|| new_TabPageIdxs == NULL
#ifdef FEAT_TEXT_PROP
|| new_popup_mask == NULL
+ || new_popup_mask_next == NULL
#endif
|| outofmem)
{
***************
*** 9264,9269 ****
--- 9317,9323 ----
VIM_CLEAR(new_TabPageIdxs);
#ifdef FEAT_TEXT_PROP
VIM_CLEAR(new_popup_mask);
+ VIM_CLEAR(new_popup_mask_next);
#endif
}
else
***************
*** 9353,9358 ****
--- 9407,9413 ----
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,9426 ****
--- 9476,9482 ----
VIM_CLEAR(TabPageIdxs);
#ifdef FEAT_TEXT_PROP
VIM_CLEAR(popup_mask);
+ VIM_CLEAR(popup_mask_next);
#endif
}
***************
*** 10027,10033 ****
}
#ifdef FEAT_TEXT_PROP
! // this doesn't work when tere are popups visible
if (popup_visible)
return FAIL;
#endif
--- 10083,10089 ----
}
#ifdef FEAT_TEXT_PROP
! // this doesn't work when there are popups visible
if (popup_visible)
return FAIL;
#endif
*** ../vim-8.1.1516/src/proto/screen.pro 2019-06-08 16:01:10.643493653
+0200
--- src/proto/screen.pro 2019-06-10 18:54:20.638071804 +0200
***************
*** 16,22 ****
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);
--- 16,21 ----
*** ../vim-8.1.1516/src/ui.c 2019-05-29 22:28:25.763184805 +0200
--- src/ui.c 2019-06-10 18:47:41.463937832 +0200
***************
*** 3242,3256 ****
|| curwin->w_cursor.col != old_cursor.col)
count |= CURSOR_MOVED; /* Cursor has moved */
! #ifdef FEAT_FOLDING
if (mouse_char == '+')
count |= MOUSE_FOLD_OPEN;
else if (mouse_char != ' ')
count |= MOUSE_FOLD_CLOSE;
! #endif
return count;
}
/*
* Compute the position in the buffer line from the posn on the screen in
--- 3242,3260 ----
|| curwin->w_cursor.col != old_cursor.col)
count |= CURSOR_MOVED; /* Cursor has moved */
! # ifdef FEAT_FOLDING
if (mouse_char == '+')
count |= MOUSE_FOLD_OPEN;
else if (mouse_char != ' ')
count |= MOUSE_FOLD_CLOSE;
! # 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,3353 ****
* Returns NULL when something is wrong.
*/
win_T *
! mouse_find_win(int *rowp, int *colp UNUSED)
{
frame_T *fp;
win_T *wp;
--- 3351,3357 ----
* Returns NULL when something is wrong.
*/
win_T *
! mouse_find_win(int *rowp, int *colp)
{
frame_T *fp;
win_T *wp;
*** ../vim-8.1.1516/src/popupwin.c 2019-06-10 13:10:45.370588270 +0200
--- src/popupwin.c 2019-06-10 21:11:25.503031889 +0200
***************
*** 571,578 ****
|| org_width != wp->w_width
|| org_height != wp->w_height)
{
! // TODO: redraw only windows that were below the popup.
! redraw_all_later(NOT_VALID);
popup_mask_refresh = TRUE;
}
}
--- 571,577 ----
|| org_width != wp->w_width
|| org_height != wp->w_height)
{
! redraw_all_later(VALID);
popup_mask_refresh = TRUE;
}
}
*** ../vim-8.1.1516/src/globals.h 2019-06-08 16:01:10.639493666 +0200
--- src/globals.h 2019-06-10 20:09:08.205952450 +0200
***************
*** 73,78 ****
--- 73,79 ----
#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);
*** ../vim-8.1.1516/src/testdir/popupbounce.vim 2019-06-10 21:20:02.572729769
+0200
--- src/testdir/popupbounce.vim 2019-06-10 20:23:57.374515240 +0200
***************
*** 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
*** ../vim-8.1.1516/Filelist 2019-06-09 13:42:36.428522167 +0200
--- Filelist 2019-06-10 21:12:55.398625778 +0200
***************
*** 152,157 ****
--- 152,158 ----
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 \
*** ../vim-8.1.1516/src/version.c 2019-06-10 17:43:42.706045520 +0200
--- src/version.c 2019-06-10 21:20:13.196683104 +0200
***************
*** 779,780 ****
--- 779,782 ----
{ /* Add new patch number below this line */
+ /**/
+ 1517,
/**/
--
hundred-and-one symptoms of being an internet addict:
148. You find it easier to dial-up the National Weather Service
Weather/your_town/now.html than to simply look out the window.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/201906101924.x5AJOfjX023704%40masaka.moolenaar.net.
For more options, visit https://groups.google.com/d/optout.