[Concept,35/42] video: Provide a buffer to hold pixels behind the cursor

Message ID 20250919201507.4024144-36-sjg@u-boot.org
State New
Headers
Series video: Support a cursor more generally |

Commit Message

Simon Glass Sept. 19, 2025, 8:14 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

Drawing the cursor is a destructive operation, so we must save the
previous contents of the affected part of the framebuffer, so it can be
restored afterwards.

Add this to the cursor info and set it up when probing the console
device.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/video/console_core.c        | 41 ++++++++++++++++++++++++++++-
 drivers/video/console_truetype.c    |  4 +++
 drivers/video/vidconsole_internal.h | 10 +++++++
 include/video_console.h             |  4 +++
 4 files changed, 58 insertions(+), 1 deletion(-)
  

Patch

diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c
index 6db42e63ea9..b1688e717c9 100644
--- a/drivers/video/console_core.c
+++ b/drivers/video/console_core.c
@@ -9,6 +9,8 @@ 
 #include <video.h>
 #include <video_console.h>
 #include <dm.h>
+#include <malloc.h>
+#include <spl.h>
 #include <video_font.h>
 #include "vidconsole_internal.h"
 
@@ -198,9 +200,46 @@  int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv,
 	return 0;
 }
 
+int console_alloc_cursor(struct udevice *dev)
+{
+	struct vidconsole_priv *vc_priv;
+	struct vidconsole_cursor *curs;
+	struct video_priv *vid_priv;
+	struct udevice *vid;
+	int save_count;
+
+	if (!CONFIG_IS_ENABLED(CURSOR) || xpl_phase() < PHASE_BOARD_R)
+		return 0;
+
+	vc_priv = dev_get_uclass_priv(dev);
+	vid = dev_get_parent(dev);
+	vid_priv = dev_get_uclass_priv(vid);
+	curs = &vc_priv->curs;
+
+	/* Allocate cursor save buffer for maximum possible cursor height */
+	save_count = vid_priv->ysize * VIDCONSOLE_CURSOR_WIDTH;
+	curs->save_data = malloc(save_count * sizeof(u32));
+	if (!curs->save_data)
+		return -ENOMEM;
+
+	return 0;
+}
+
 int console_probe(struct udevice *dev)
 {
-	return console_set_font(dev, fonts);
+	int ret;
+
+	ret = console_set_font(dev, fonts);
+	if (ret)
+		return ret;
+
+	if (CONFIG_IS_ENABLED(CURSOR) && xpl_phase() == PHASE_BOARD_R) {
+		ret = console_alloc_cursor(dev);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
 }
 
 const char *console_simple_get_font_size(struct udevice *dev, uint *sizep)
diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c
index e215a3e0e54..fc2985ed92f 100644
--- a/drivers/video/console_truetype.c
+++ b/drivers/video/console_truetype.c
@@ -1111,6 +1111,10 @@  static int console_truetype_probe(struct udevice *dev)
 
 	debug("%s: ready\n", __func__);
 
+	ret = console_alloc_cursor(dev);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
diff --git a/drivers/video/vidconsole_internal.h b/drivers/video/vidconsole_internal.h
index c008b9cf7d3..4cb6ba4e15f 100644
--- a/drivers/video/vidconsole_internal.h
+++ b/drivers/video/vidconsole_internal.h
@@ -123,6 +123,16 @@  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);
 
+/**
+ * console_alloc_cursor() - Allocate cursor save buffer
+ *
+ * Allocates memory for saving pixels under the cursor
+ *
+ * @dev: vidconsole device
+ * Return: 0 if success, -ENOMEM if allocation fails
+ */
+int console_alloc_cursor(struct udevice *dev);
+
 /**
  * console probe function.
  *
diff --git a/include/video_console.h b/include/video_console.h
index b40253b218d..ffe331c5803 100644
--- a/include/video_console.h
+++ b/include/video_console.h
@@ -32,6 +32,8 @@  enum {
  * @enabled:	cursor is active (e.g. during readline)
  * @visible:	cursor is currently visible
  * @indent:	indent subsequent lines to the same position as the first line
+ * @saved:	true if save_data contains valid data
+ * @save_data:	saved pixels under cursor
  * @x:		cursor left X position in pixels
  * @y:		cursor top Y position in pixels
  * @height:	height of cursor in pixels
@@ -41,6 +43,8 @@  struct vidconsole_cursor {
 	bool enabled;
 	bool visible;
 	bool indent;
+	bool saved;
+	u32 *save_data;
 
 	/* filled in by get_cursor_info(): */
 	uint x;