From patchwork Fri Jan 30 03:58:28 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1780 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org Authentication-Results: mail.u-boot.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=RZPkgCgr; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 0E2F6697ED for ; Thu, 29 Jan 2026 20:59:19 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id a8ny6FxBX6Ki for ; Thu, 29 Jan 2026 20:59:18 -0700 (MST) Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 9ABA7697F0 for ; Thu, 29 Jan 2026 20:59:17 -0700 (MST) Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 67AAC697CB for ; Thu, 29 Jan 2026 20:59:15 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id qu1R0BKAYCIh for ; Thu, 29 Jan 2026 20:59:15 -0700 (MST) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.167.178; helo=mail-oi1-f178.google.com; envelope-from=sjg@chromium.org; receiver=u-boot.org Received: from mail-oi1-f178.google.com (mail-oi1-f178.google.com [209.85.167.178]) by mail.u-boot.org (Postfix) with ESMTPS id F339C69738 for ; Thu, 29 Jan 2026 20:59:14 -0700 (MST) Received: by mail-oi1-f178.google.com with SMTP id 5614622812f47-45f015a3259so706899b6e.2 for ; Thu, 29 Jan 2026 19:59:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1769745553; x=1770350353; darn=u-boot.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Llif9hck2vul2cgSiXg6WNyHvLzQGgnqAzchzZU9OfA=; b=RZPkgCgrmTGlgGUfw7It8X/T/iU5mu0baHCMTAEoMpf/HcWKrdIm+3MEJe0DBEGJOS teT+CqK3fykme8iByNDwIjkUo8sujK3k/K829DGy3UvQSlodMDE6hG2/qrnZ7W674t1a 3+NPCIrIrHYtPYnoi8Hsg1J1d6EKaI8cktTXw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769745553; x=1770350353; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Llif9hck2vul2cgSiXg6WNyHvLzQGgnqAzchzZU9OfA=; b=kxm9Y+ORUy5lnxLGaeJFTpJKhNJ6EvBwHSvgZQO9tzewG7tgPuCIQi+ibA5R/WIfJ0 iD1cWzIi3ooOzi8F6wbFqZyiyrm8X9GBvCxjhfNb5DmIeItGiVla4xZIWe4b8WxUvsxz 4sH7PrQzt5EgA/epEuJrDSJ6z/ie3Mkhco4fB6ZQrINGiNFofDIxOb3FeG9aIKWOhUrl G7yFrKKy+xV8bWNCCkXCpHIbEMPUiK4N+gouLyIgcZAmE9YNQlmvpv8gJGmAzTi82zMo 6csq0De82plE5RZ7HI+W2cPJn6KTnTozq+Arhh+OiGVJReBi8Q6/XoV2ai9BxBZ5tR+Y BLJg== X-Gm-Message-State: AOJu0YzvUOKfD+KwvQi9Qj/t7XxJ8cLhBFN9lhVIYLJFZxSykS15MTmC JkHsq1O/ckedVvNZ/uGiKCjfZVvtMRqPIGbnZhH1i6Q5meKSdopi12nnpgSMcZPmkA/ETM8iWvj v02FqWA== X-Gm-Gg: AZuq6aJS6hNsYE24CUlxN2LsaVaxyI83/qLykFM62RQ56sqFqhtiBSHsZZVLnrSHHYt qlOicNfGzx3Xd12ZLEfRdHNMiR8ducXDdET7Rww+xNBC2Pjd9SDlXqlw7tkakCsgft8VhJ+C8GY Mks8MPJcDyZ5GgxXwJIN0KjB/AqQCLfXlJZVqWzbRC81BbVFAtCagr0Ar5fbNl3JTth1/tKYrpS ee3wTNz4vtrNVGZU6/+aZbH1VVU0Xrvfb8A5LaVjkags/Zx7PqGHcF3CA2gM4soHvMwSUcB7VeV 61QkinD3dNWX9IaybifTmUZRolX4XbLYhxZTVNQTvKWN2rMbCChTQw3yYFHatSbHpcxZVqCDu/G dvOOmHfDqUWvE5LCNTCa+GE5b+OtCVID/ju0eMtEZSILlAQwi4n26shk2uKFT+lgdYGQnozT94I +vtiyaQCAfe3tqGhwd X-Received: by 2002:a05:6820:7610:b0:663:12e7:c51c with SMTP id 006d021491bc7-66312e7c86cmr161523eaf.58.1769745553325; Thu, 29 Jan 2026 19:59:13 -0800 (PST) Received: from chromium.org ([73.34.74.121]) by smtp.gmail.com with ESMTPSA id 006d021491bc7-662f9a4e491sm4128687eaf.16.2026.01.29.19.59.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Jan 2026 19:59:11 -0800 (PST) From: Simon Glass X-Google-Original-From: Simon Glass To: U-Boot Concept Date: Thu, 29 Jan 2026 20:58:28 -0700 Message-ID: <20260130035849.3580212-6-simon.glass@canonical.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260130035849.3580212-1-simon.glass@canonical.com> References: <20260130035849.3580212-1-simon.glass@canonical.com> MIME-Version: 1.0 Message-ID-Hash: URUD6RHDWHFKQFQKXJUH7YR5O72ZJTGN X-Message-ID-Hash: URUD6RHDWHFKQFQKXJUH7YR5O72ZJTGN X-MailFrom: sjg@chromium.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , "Claude Opus 4 . 5" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 05/19] test: Display message at top right during video test delay List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: When a message is passed to video_compress_fb_() and a delay is active (via -V flag or LOG_DEBUG), display the message at the top right of the screen. The affected framebuffer region is saved before drawing and restored afterwards, so the message is only visible during the delay. Add save_video() and restore_video() functions in test/dm/video.c to handle saving and restoring framebuffer regions. The save buffer is allocated on first use and stored in uts->video_save, then freed in ut_uninit_state(). Guard the message display with CONFIG_UNIT_TEST since the unit_test_state structure is only available when unit tests are enabled. This helps identify which frame check is being displayed when debugging video tests. Co-developed-by: Claude Opus 4.5 Signed-off-by: Simon Glass --- doc/develop/expo.rst | 7 +++ include/test/test.h | 5 ++ test/dm/video.c | 123 ++++++++++++++++++++++++++++++++++++++++--- test/test-main.c | 2 + 4 files changed, 130 insertions(+), 7 deletions(-) diff --git a/doc/develop/expo.rst b/doc/develop/expo.rst index 7ef714be3da..71e227c532d 100644 --- a/doc/develop/expo.rst +++ b/doc/develop/expo.rst @@ -824,6 +824,13 @@ For example, to watch an expo test render with a visible display:: ./u-boot -T -l -V 500 --video_frames /tmp/good -c "ut bootstd expo_render_image" +When using ``-V`` or with ``LOG_DEBUG`` enabled, some video tests call +ut_check_video() to display a message at the top right corner of the screen +identifying the current frame check. This helps identify which assertion is +being displayed when debugging test failures. The message is automatically +removed after the delay, so it does not affect the framebuffer checksums used by +video tests. + The :doc:`../usage/cmd/sb` ``grid`` subcommand can be used to overlay a grid on the display, to help with checking alignment of objects. The grid size defaults to 0x20 pixels but can be specified as a parameter. diff --git a/include/test/test.h b/include/test/test.h index 56e25f6fa9d..c3b251e2cd4 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -6,6 +6,7 @@ #ifndef __TEST_TEST_H #define __TEST_TEST_H +#include #include #include @@ -100,6 +101,8 @@ struct ut_arg { * @arg_error: Set if ut_str/int/bool() detects a type mismatch * @keep_record: Preserve console recording when ut_fail() is called * @emit_result: Emit result line after each test completes + * @video_ctx: Vidconsole context for test message display (allocated on use) + * @video_save: Saved framebuffer region for video tests * @priv: Private data for tests to use as needed */ struct unit_test_state { @@ -134,6 +137,8 @@ struct unit_test_state { bool arg_error; bool keep_record; bool emit_result; + void *video_ctx; + struct abuf video_save; char priv[UT_PRIV_SIZE]; }; diff --git a/test/dm/video.c b/test/dm/video.c index 421d50df064..f97e2183a64 100644 --- a/test/dm/video.c +++ b/test/dm/video.c @@ -138,8 +138,106 @@ static int video_write_bmp(struct unit_test_state *uts, struct udevice *dev, return ret; } -static int video_compress_fb_(struct unit_test_state *uts, struct udevice *dev, - bool use_copy, const char *msg) +/** + * save_video() - Save a portion of the framebuffer + * + * Saves the top portion of the framebuffer so it can be restored later. + * The buffer is allocated on first use and stored in uts->video_save. + * + * @uts: Unit test state + * @dev: Video device + * @lines: Number of lines to save + * Return: 0 on success, -ve on error + */ +static int save_video(struct unit_test_state *uts, struct udevice *dev, + uint lines) +{ + struct video_priv *priv = dev_get_uclass_priv(dev); + int size; + + size = priv->line_length * lines; + if (size > priv->fb_size) + return -EINVAL; + + /* Allocate/resize the save buffer to exact size needed */ + if (!abuf_realloc(&uts->video_save, size)) + return -ENOMEM; + + memcpy(abuf_data(&uts->video_save), priv->fb, size); + + return 0; +} + +/** + * restore_video() - Restore a saved portion of the framebuffer + * + * Restores the framebuffer region previously saved by save_video(). + * + * @uts: Unit test state + * @dev: Video device + * Return: 0 on success, -ve on error + */ +static int restore_video(struct unit_test_state *uts, struct udevice *dev) +{ + struct video_priv *priv = dev_get_uclass_priv(dev); + + if (!abuf_size(&uts->video_save)) + return -ENOENT; + + memcpy(priv->fb, abuf_data(&uts->video_save), + abuf_size(&uts->video_save)); + + return 0; +} + +/** + * show_test_msg() - Display a test message at the top right of the screen + * + * @uts: Unit test state + * @dev: Video device + * @msg: Message to display + * Return: true if framebuffer was saved and needs restoring, false otherwise + */ +static bool show_test_msg(struct unit_test_state *uts, struct udevice *dev, + const char *msg) +{ + struct video_priv *priv = dev_get_uclass_priv(dev); + struct vidconsole_ctx *ctx = uts->video_ctx; + struct udevice *con; + bool saved = false; + int len = strlen(msg); + int x, ret; + + ret = uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &con); + if (ret) + return false; + + /* Allocate context on first use and select 8x16 font */ + if (!ctx) { + ret = vidconsole_ctx_new(con, (void **)&ctx); + if (ret) + return false; + uts->video_ctx = ctx; + vidconsole_select_font(con, ctx, "8x16", 0); + } + + /* Calculate position at top right */ + x = priv->xsize - (len + 2) * ctx->x_charsize; + + /* Save the affected region (one line) */ + if (!save_video(uts, dev, ctx->y_charsize)) + saved = true; + + /* Draw the message */ + vidconsole_set_cursor_pos(con, ctx, x, 0); + vidconsole_put_string(con, ctx, msg); + video_manual_sync(dev, VIDSYNC_COPY | VIDSYNC_FLUSH); + + return saved; +} + +int video_compress_fb_(struct unit_test_state *uts, struct udevice *dev, + bool use_copy, const char *msg) { struct sandbox_state *state = state_get_current(); struct video_priv *priv = dev_get_uclass_priv(dev); @@ -176,10 +274,21 @@ static int video_compress_fb_(struct unit_test_state *uts, struct udevice *dev, } /* provide a useful delay if -V flag is used or LOG_DEBUG is set */ - if (state->video_test) - mdelay(state->video_test); - else if (_DEBUG) - mdelay(300); + if (state->video_test || _DEBUG) { + int delay = state->video_test ? state->video_test : 300; + bool saved = false; + + if (msg) + saved = show_test_msg(uts, dev, msg); + + mdelay(delay); + + /* Restore the framebuffer region */ + if (saved) { + restore_video(uts, dev); + video_manual_sync(dev, VIDSYNC_COPY | VIDSYNC_FLUSH); + } + } return destlen; } @@ -213,7 +322,7 @@ int ut_check_video(struct unit_test_state *uts, const char *msg) if (ret) return ret; - return video_compress_fb(uts, dev, false); + return video_compress_fb_(uts, dev, false, msg); } /* diff --git a/test/test-main.c b/test/test-main.c index a2c4e32423b..5db35b59760 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -87,6 +87,8 @@ void ut_uninit_state(struct unit_test_state *uts) os_free(uts->fdt_copy); os_free(uts->other_fdt); } + /* video_ctx is freed when the vidconsole is unbound */ + abuf_uninit(&uts->video_save); } /**