
From: Simon Glass <sjg@chromium.org> Save the pixels overwritten by the cursor into the save area. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_core.c | 63 ++++++++++++++++++++++++++--- drivers/video/vidconsole-uclass.c | 36 +++++++++++++++++ drivers/video/vidconsole_internal.h | 15 ++++++- include/video_console.h | 16 +++++++- 4 files changed, 122 insertions(+), 8 deletions(-) diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c index 4fab5a2605e..3f3efb94ab1 100644 --- a/drivers/video/console_core.c +++ b/drivers/video/console_core.c @@ -190,8 +190,9 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv, bool direction) { - int step, line_step, pbytes, ret; + int step, line_step, pbytes, ret, row; void *line, *dst; + u32 *save_ptr; uint value; ret = check_bpix_support(vid_priv->bpix); @@ -207,20 +208,72 @@ int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv, line_step = vid_priv->line_length; } + /* we should not already have saved data */ + if (curs->saved) { + debug("Trying to show cursor but data is already saved\n"); + return -EINVAL; + } + /* Figure out where to write the cursor in the frame buffer */ line = vid_priv->fb + curs->y * vid_priv->line_length + curs->x * VNBYTES(vid_priv->bpix); + /* save pixels under cursor and draw new cursor in one pass */ value = vid_priv->colour_fg; - - for (int row = 0; row < curs->height; row++) { + save_ptr = curs->save_data; + for (row = 0; row < curs->height; row++) { dst = line; for (int col = 0; col < VIDCONSOLE_CURSOR_WIDTH; col++) - fill_pixel_and_goto_next(&dst, value, pbytes, step); - + *save_ptr++ = swap_pixel_and_goto_next(&dst, value, + pbytes, step); line += line_step; } + curs->saved = true; + + return 0; +} + +int cursor_hide(struct vidconsole_cursor *curs, struct video_priv *vid_priv, + bool direction) +{ + int step, line_step, pbytes, ret; + void *line, *dst; + + ret = check_bpix_support(vid_priv->bpix); + if (ret) + return ret; + + pbytes = VNBYTES(vid_priv->bpix); + if (direction) { + step = -pbytes; + line_step = -vid_priv->line_length; + } else { + step = pbytes; + line_step = vid_priv->line_length; + } + + /* Trying to hide cursor - we should have saved data */ + if (!curs->saved) { + debug("Trying to hide cursor but no data was saved\n"); + return -EINVAL; + } + + /* Figure out where to write the cursor in the frame buffer */ + line = vid_priv->fb + curs->y * vid_priv->line_length + + curs->x * VNBYTES(vid_priv->bpix); + + /* Restore saved pixels */ + u32 *save_ptr = curs->save_data; + dst = line; + for (int row = 0; row < curs->height; row++) { + void *row_dst = dst; + for (int col = 0; col < VIDCONSOLE_CURSOR_WIDTH; col++) + fill_pixel_and_goto_next(&row_dst, *save_ptr++, pbytes, + step); + dst += line_step; + } + curs->saved = false; return 0; } diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 15b62d160cd..3621714c742 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -71,6 +71,9 @@ static int vidconsole_back(struct udevice *dev) return ret; } + /* Hide cursor at old position if it's visible */ + vidconsole_hide_cursor(dev); + priv->xcur_frac -= VID_TO_POS(priv->x_charsize); if (priv->xcur_frac < priv->xstart_frac) { priv->xcur_frac = (priv->cols - 1) * @@ -128,6 +131,9 @@ void vidconsole_set_cursor_pos(struct udevice *dev, int x, int y) { struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + /* Hide cursor at old position if it's visible */ + vidconsole_hide_cursor(dev); + priv->xcur_frac = VID_TO_POS(x); priv->xstart_frac = priv->xcur_frac; priv->ycur = y; @@ -473,6 +479,9 @@ int vidconsole_put_char(struct udevice *dev, char ch) struct vidconsole_priv *priv = dev_get_uclass_priv(dev); int cp, ret; + /* Hide cursor to avoid artifacts */ + vidconsole_hide_cursor(dev); + if (priv->escape) { vidconsole_escape_char(dev, ch); return 0; @@ -752,6 +761,33 @@ int vidconsole_show_cursor(struct udevice *dev) return 0; } +int vidconsole_hide_cursor(struct udevice *dev) +{ + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + struct vidconsole_cursor *curs = &priv->curs; + int ret; + + if (!curs->visible) + return 0; + + /* If the driver stored cursor line and height, use them for drawing */ + if (curs->height) { + struct udevice *vid = dev_get_parent(dev); + struct video_priv *vid_priv = dev_get_uclass_priv(vid); + + ret = cursor_hide(curs, vid_priv, NORMAL_DIRECTION); + if (ret) + return ret; + + /* Update display damage for cursor area */ + video_damage(vid, curs->x, curs->y, VIDCONSOLE_CURSOR_WIDTH, + curs->height); + } + + curs->visible = false; + + return 0; +} #endif /* CONFIG_CURSOR */ int vidconsole_mark_start(struct udevice *dev) diff --git a/drivers/video/vidconsole_internal.h b/drivers/video/vidconsole_internal.h index 93f9c7b4e56..241be149ac9 100644 --- a/drivers/video/vidconsole_internal.h +++ b/drivers/video/vidconsole_internal.h @@ -112,7 +112,7 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri struct video_fontdata *fontdata, bool direction); /** - * cursor_show() - Draw a simple vertical cursor + * cursor_show() - Show cursor by saving and drawing pixels * * @curs: cursor information * @vid_priv: video-device info @@ -130,11 +130,22 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri *|---!!we're starting from upper left char corner| *|-----------------------------------------------| * - * Return: 0, if success, or else error code. + * Return: 0 on success, -EINVAL if cursor data already saved */ int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv, bool direction); +/** + * cursor_hide() - Hide cursor by restoring saved pixels + * + * @curs: cursor information + * @vid_priv: video-device info + * @direction: controls cursor orientation (normal or flipped) + * Return: 0 if success, -EINVAL if no cursor data was saved + */ +int cursor_hide(struct vidconsole_cursor *curs, struct video_priv *vid_priv, + bool direction); + /** * console_alloc_cursor() - Allocate cursor save buffer * diff --git a/include/video_console.h b/include/video_console.h index ffe331c5803..9005e9f4442 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -462,6 +462,16 @@ int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf); */ int vidconsole_show_cursor(struct udevice *dev); +/** + * vidconsole_hide_cursor() - Hide the cursor + * + * Hides the cursor if it's currently visible + * + * @dev: Console device to use + * Return: 0 if OK, -ve on error + */ +int vidconsole_hide_cursor(struct udevice *dev); + /** * vidconsole_readline_start() - Enable cursor for all video consoles * @@ -485,6 +495,11 @@ static inline int vidconsole_show_cursor(struct udevice *dev) return 0; } +static inline int vidconsole_hide_cursor(struct udevice *dev) +{ + return 0; +} + static inline void vidconsole_readline_start(bool indent) { } @@ -501,7 +516,6 @@ static inline void cli_index_adjust(struct vidconsole_priv *priv, int by) } /** - * vidconsole_push_colour() - Temporarily change the font colour * * @dev: Device to adjust -- 2.43.0