[Concept,22/22] video: sandbox: Add test for sync() damage rectangle

Message ID 20251003165525.440173-23-sjg@u-boot.org
State New
Headers
Series video: Enhancements to support a pointer |

Commit Message

Simon Glass Oct. 3, 2025, 4:55 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

Add a test that verifies the sandbox SDL driver receives the correct
damage rectangle in its sync() method. The test:

- Clears the display and verifies full-screen damage is passed to sync()
- Writes text at a specific position and verifies smaller damage region
- Draws a box and verifies the damage matches the box dimensions

The damage rectangle is recorded in sandbox_sdl_plat.last_sync_damage
and can be retrieved using sandbox_sdl_get_sync_damage() for testing
purposes.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/video/sandbox_sdl.c | 23 +++++++--
 include/dm/test.h           | 15 ++++++
 test/dm/video.c             | 96 +++++++++++++++++++++++++++++++++++++
 3 files changed, 131 insertions(+), 3 deletions(-)
  

Patch

diff --git a/drivers/video/sandbox_sdl.c b/drivers/video/sandbox_sdl.c
index 67b4b6c7911..fc5843a2822 100644
--- a/drivers/video/sandbox_sdl.c
+++ b/drivers/video/sandbox_sdl.c
@@ -129,22 +129,39 @@  static int sandbox_sdl_bind(struct udevice *dev)
 
 static int sandbox_sdl_video_sync(struct udevice *vid, uint flags)
 {
-	struct video_priv *priv = dev_get_uclass_priv(vid);
+	struct sandbox_sdl_plat *plat = dev_get_plat(vid);
+	struct video_priv *uc_priv = dev_get_uclass_priv(vid);
 	const struct video_bbox *damage = NULL;
 
 	if (!(flags & VIDSYNC_FLUSH))
 		return 0;
 
 	if (IS_ENABLED(CONFIG_VIDEO_DAMAGE))
-		damage = &priv->damage;
+		damage = &uc_priv->damage;
 
-	return sandbox_sdl_sync(priv->fb, damage);
+	/* Record the damage box for testing */
+	if (damage)
+		plat->last_sync_damage = *damage;
+	else
+		memset(&plat->last_sync_damage, '\0',
+		       sizeof(plat->last_sync_damage));
+
+	return sandbox_sdl_sync(uc_priv->fb, damage);
 }
 
 static const struct video_ops sandbox_sdl_ops = {
 	.sync = sandbox_sdl_video_sync,
 };
 
+int sandbox_sdl_get_sync_damage(struct udevice *dev, struct video_bbox *damage)
+{
+	struct sandbox_sdl_plat *plat = dev_get_plat(dev);
+
+	*damage = plat->last_sync_damage;
+
+	return 0;
+}
+
 static const struct udevice_id sandbox_sdl_ids[] = {
 	{ .compatible = "sandbox,lcd-sdl" },
 	{ }
diff --git a/include/dm/test.h b/include/dm/test.h
index 4aabb4603b9..10fd63e759f 100644
--- a/include/dm/test.h
+++ b/include/dm/test.h
@@ -7,6 +7,7 @@ 
 #define __DM_TEST_H
 
 #include <linux/types.h>
+#include <video_defs.h>
 
 struct udevice;
 
@@ -157,6 +158,7 @@  extern struct unit_test_state global_dm_test_state;
  *	2=upside down, 3=90 degree counterclockwise)
  * @vidconsole_drv_name: Name of video console driver (set by tests)
  * @font_size: Console font size to select (set by tests)
+ * @last_sync_damage: Last damage rectangle passed to sync() method (for testing)
  */
 struct sandbox_sdl_plat {
 	int xres;
@@ -165,6 +167,7 @@  struct sandbox_sdl_plat {
 	int rot;
 	const char *vidconsole_drv_name;
 	int font_size;
+	struct video_bbox last_sync_damage;
 };
 
 /**
@@ -232,4 +235,16 @@  void dm_leak_check_start(struct unit_test_state *uts);
  * @dms: Overall test state
  */int dm_leak_check_end(struct unit_test_state *uts);
 
+/**
+ * sandbox_sdl_get_sync_damage() - Get the last damage rect passed to sync()
+ *
+ * This is used for testing to verify that the correct damage rectangle was
+ * passed to the driver's sync() method.
+ *
+ * @dev: Video device
+ * @damage: Returns the last damage rectangle
+ * Return: 0 if OK, -ve on error
+ */
+int sandbox_sdl_get_sync_damage(struct udevice *dev, struct video_bbox *damage);
+
 #endif
diff --git a/test/dm/video.c b/test/dm/video.c
index 080297d8350..5a5d8053856 100644
--- a/test/dm/video.c
+++ b/test/dm/video.c
@@ -1372,3 +1372,99 @@  static int dm_test_video_manual_sync(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_video_manual_sync, UTF_SCAN_PDATA | UTF_SCAN_FDT);
+
+/* Test that sync() receives the correct damage rectangle */
+static int dm_test_video_sync_damage(struct unit_test_state *uts)
+{
+	struct video_bbox damage;
+	struct udevice *dev, *con;
+	struct video_priv *priv;
+
+	if (!IS_ENABLED(CONFIG_VIDEO_DAMAGE))
+		return -EAGAIN;
+
+	ut_assertok(select_vidconsole(uts, "vidconsole0"));
+	ut_assertok(video_get_nologo(uts, &dev));
+	ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
+	ut_assertok(vidconsole_select_font(con, "8x16", 0));
+	priv = dev_get_uclass_priv(dev);
+
+	/* Use manual sync to prevent interference with the test */
+	video_set_manual_sync(true);
+
+	/* Clear the display - this creates a full-screen damage and syncs */
+	video_clear(dev);
+	ut_assertok(video_manual_sync(dev, VIDSYNC_FLUSH | VIDSYNC_COPY));
+	ut_asserteq(46, video_compress_fb(uts, dev, false));
+
+	/* Get the damage rectangle that was passed to sync() */
+	ut_assertok(sandbox_sdl_get_sync_damage(dev, &damage));
+
+	/* Should be the full screen */
+	ut_assert(video_bbox_valid(&damage));
+	ut_asserteq(0, damage.x0);
+	ut_asserteq(0, damage.y0);
+	ut_asserteq(priv->xsize, damage.x1);
+	ut_asserteq(priv->ysize, damage.y1);
+
+	/* Sync again with no changes - should have empty damage */
+	ut_assertok(video_manual_sync(dev, VIDSYNC_FLUSH | VIDSYNC_COPY));
+	ut_assertok(sandbox_sdl_get_sync_damage(dev, &damage));
+	ut_assert(!video_bbox_valid(&damage));
+
+	/* Check that priv->damage is still reset to empty */
+	ut_assert(!video_bbox_valid(&priv->damage));
+
+	/* Write a small piece of text at a specific position */
+	vidconsole_putc_xy(con, VID_TO_POS(400), 67, 'T');
+
+	/* Check priv->damage before sync - should have text damage */
+	ut_assert(video_bbox_valid(&priv->damage));
+	ut_asserteq(400, priv->damage.x0);
+	ut_asserteq(67, priv->damage.y0);
+	ut_asserteq(400 + 8, priv->damage.x1);  /* 8x16 font */
+	ut_asserteq(67 + 16, priv->damage.y1);
+
+	ut_assertok(video_manual_sync(dev, VIDSYNC_FLUSH | VIDSYNC_COPY));
+
+	/* Get the damage rectangle that was passed to sync() */
+	ut_assertok(sandbox_sdl_get_sync_damage(dev, &damage));
+
+	/* The damage should cover just the character */
+	ut_assert(video_bbox_valid(&damage));
+	ut_asserteq(400, damage.x0);
+	ut_asserteq(67, damage.y0);
+	ut_asserteq(400 + 8, damage.x1);
+	ut_asserteq(67 + 16, damage.y1);
+
+	/* Check priv->damage after sync - should be reset to empty */
+	ut_assert(!video_bbox_valid(&priv->damage));
+
+	/* Draw a filled box at a different position */
+	ut_assertok(video_draw_box(dev, 200, 300, 250, 340, 1, 0xffffff, true));
+
+	/* Check priv->damage before sync - should have box damage */
+	ut_assert(video_bbox_valid(&priv->damage));
+	ut_asserteq(200, priv->damage.x0);
+	ut_asserteq(300, priv->damage.y0);
+	ut_asserteq(250, priv->damage.x1);
+	ut_asserteq(340, priv->damage.y1);
+
+	ut_assertok(video_manual_sync(dev, VIDSYNC_FLUSH | VIDSYNC_COPY));
+
+	/* Get the damage rectangle for the box */
+	ut_assertok(sandbox_sdl_get_sync_damage(dev, &damage));
+
+	/* The damage should cover the box area */
+	ut_assert(video_bbox_valid(&damage));
+	ut_asserteq(200, damage.x0);
+	ut_asserteq(300, damage.y0);
+	ut_asserteq(250, damage.x1);
+	ut_asserteq(340, damage.y1);
+
+	/* Check priv->damage after sync - should be reset to inverted/empty */
+	ut_assert(!video_bbox_valid(&priv->damage));
+
+	return 0;
+}
+DM_TEST(dm_test_video_sync_damage, UTF_SCAN_PDATA | UTF_SCAN_FDT);